summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Leonhardt <sebastian.leonhardt@web.de>2016-01-08 01:05:36 +0100
committerSolomon Peachy <pizza@shaftnet.org>2024-06-30 17:24:16 -0400
commit102c3742487dba76ec72d5f56a2c3041344b2d68 (patch)
tree4931ad34d2cc0bac56d9984b9ead355d012ad63a
parent6f1e67e5e318ba2fd0f5ec1892c7b6633ec6521c (diff)
downloadrockbox-102c3742487dba76ec72d5f56a2c3041344b2d68.tar.gz
rockbox-102c3742487dba76ec72d5f56a2c3041344b2d68.zip
added xrick game
original xrick code by 'BigOrno' at: http://www.bigorno.net/xrick/ Rockbox port, plus bugfixes at: https://github.com/pierluigi-vicinanza/xrick Further changes: * Additonal fixes from g#3026 * Port to modern plugin API * Add Pluginlib keymap fallback * Support all >1bpp screens * Fix build warnings in miniz * Better error message when resources are missing Change-Id: Id83928bc2539901b0221692f65cbca41389c58e7
-rw-r--r--apps/plugins/CATEGORIES1
-rw-r--r--apps/plugins/SUBDIRS4
-rw-r--r--apps/plugins/xrick/3rd_party/miniz/miniz.c4928
-rw-r--r--apps/plugins/xrick/README.md88
-rw-r--r--apps/plugins/xrick/README.rockbox16
-rw-r--r--apps/plugins/xrick/SOURCES40
-rw-r--r--apps/plugins/xrick/config.h58
-rw-r--r--apps/plugins/xrick/control.c24
-rw-r--r--apps/plugins/xrick/control.h41
-rw-r--r--apps/plugins/xrick/data/img.c23
-rw-r--r--apps/plugins/xrick/data/img.h39
-rw-r--r--apps/plugins/xrick/data/pics.c29
-rw-r--r--apps/plugins/xrick/data/pics.h41
-rw-r--r--apps/plugins/xrick/data/sounds.c44
-rw-r--r--apps/plugins/xrick/data/sounds.h87
-rw-r--r--apps/plugins/xrick/data/sprites.c22
-rw-r--r--apps/plugins/xrick/data/sprites.h70
-rw-r--r--apps/plugins/xrick/data/tiles.c22
-rw-r--r--apps/plugins/xrick/data/tiles.h70
-rw-r--r--apps/plugins/xrick/debug.h84
-rw-r--r--apps/plugins/xrick/devtools.c247
-rw-r--r--apps/plugins/xrick/devtools.h25
-rw-r--r--apps/plugins/xrick/draw.c702
-rw-r--r--apps/plugins/xrick/draw.h65
-rw-r--r--apps/plugins/xrick/e_bomb.c158
-rw-r--r--apps/plugins/xrick/e_bomb.h36
-rw-r--r--apps/plugins/xrick/e_bonus.c60
-rw-r--r--apps/plugins/xrick/e_bonus.h25
-rw-r--r--apps/plugins/xrick/e_box.c109
-rw-r--r--apps/plugins/xrick/e_box.h25
-rw-r--r--apps/plugins/xrick/e_bullet.c84
-rw-r--r--apps/plugins/xrick/e_bullet.h32
-rw-r--r--apps/plugins/xrick/e_rick.c606
-rw-r--r--apps/plugins/xrick/e_rick.h50
-rw-r--r--apps/plugins/xrick/e_sbonus.c88
-rw-r--r--apps/plugins/xrick/e_sbonus.h30
-rw-r--r--apps/plugins/xrick/e_them.c738
-rw-r--r--apps/plugins/xrick/e_them.h31
-rw-r--r--apps/plugins/xrick/ents.c540
-rw-r--r--apps/plugins/xrick/ents.h118
-rw-r--r--apps/plugins/xrick/game.c722
-rw-r--r--apps/plugins/xrick/game.h73
-rw-r--r--apps/plugins/xrick/maps.c253
-rw-r--r--apps/plugins/xrick/maps.h159
-rw-r--r--apps/plugins/xrick/rects.c57
-rw-r--r--apps/plugins/xrick/rects.h32
-rw-r--r--apps/plugins/xrick/res_magic.c18
-rw-r--r--apps/plugins/xrick/resources.c1297
-rw-r--r--apps/plugins/xrick/resources.h165
-rw-r--r--apps/plugins/xrick/scr_gameover.c92
-rw-r--r--apps/plugins/xrick/scr_getname.c290
-rw-r--r--apps/plugins/xrick/scr_imain.c170
-rw-r--r--apps/plugins/xrick/scr_imap.c293
-rw-r--r--apps/plugins/xrick/scr_pause.c50
-rw-r--r--apps/plugins/xrick/scr_xrick.c101
-rw-r--r--apps/plugins/xrick/screens.h74
-rw-r--r--apps/plugins/xrick/scroller.c165
-rw-r--r--apps/plugins/xrick/scroller.h31
-rw-r--r--apps/plugins/xrick/system/basic_funcs.c33
-rw-r--r--apps/plugins/xrick/system/basic_funcs.h141
-rw-r--r--apps/plugins/xrick/system/basic_types.h48
-rw-r--r--apps/plugins/xrick/system/main_rockbox.c43
-rw-r--r--apps/plugins/xrick/system/miniz_config.h38
-rw-r--r--apps/plugins/xrick/system/rockboxcodes.h110
-rw-r--r--apps/plugins/xrick/system/sysarg_rockbox.c49
-rw-r--r--apps/plugins/xrick/system/sysevt_rockbox.c156
-rw-r--r--apps/plugins/xrick/system/sysfile_rockbox.c122
-rw-r--r--apps/plugins/xrick/system/sysmem_rockbox.c156
-rw-r--r--apps/plugins/xrick/system/sysmenu_rockbox.c200
-rw-r--r--apps/plugins/xrick/system/sysmenu_rockbox.h32
-rw-r--r--apps/plugins/xrick/system/syssnd_rockbox.c483
-rw-r--r--apps/plugins/xrick/system/syssnd_rockbox.h48
-rw-r--r--apps/plugins/xrick/system/system.h178
-rw-r--r--apps/plugins/xrick/system/system_rockbox.c262
-rw-r--r--apps/plugins/xrick/system/sysvid_rockbox.c402
-rw-r--r--apps/plugins/xrick/util.c230
-rw-r--r--apps/plugins/xrick/util.h29
-rw-r--r--apps/plugins/xrick/xrick.make31
-rw-r--r--docs/CREDITS127
-rwxr-xr-xmanual/plugins/images/ss-xrick-220x176x16.pngbin0 -> 7938 bytes
-rwxr-xr-xmanual/plugins/images/ss-xrick-240x320x16.pngbin0 -> 9160 bytes
-rwxr-xr-xmanual/plugins/images/ss-xrick-320x240x16.pngbin0 -> 9346 bytes
-rw-r--r--manual/plugins/main.tex5
-rwxr-xr-xmanual/plugins/xrick.tex107
-rw-r--r--utils/rbutilqt/base/playerbuildinfo.cpp1
-rw-r--r--utils/rbutilqt/base/playerbuildinfo.h1
-rw-r--r--utils/rbutilqt/gui/selectiveinstallwidget.cpp1
-rw-r--r--utils/rbutilqt/rbutil.ini1
88 files changed, 16514 insertions, 62 deletions
diff --git a/apps/plugins/CATEGORIES b/apps/plugins/CATEGORIES
index c91d02ade8..5e22bea980 100644
--- a/apps/plugins/CATEGORIES
+++ b/apps/plugins/CATEGORIES
@@ -200,5 +200,6 @@ wavview,viewers
200wolf3d,games 200wolf3d,games
201wormlet,games 201wormlet,games
202xobox,games 202xobox,games
203xrick,games
203xworld,games 204xworld,games
204zxbox,viewers 205zxbox,viewers
diff --git a/apps/plugins/SUBDIRS b/apps/plugins/SUBDIRS
index 7884989d1c..c874927205 100644
--- a/apps/plugins/SUBDIRS
+++ b/apps/plugins/SUBDIRS
@@ -89,3 +89,7 @@ lua
89lua_scripts 89lua_scripts
90picross 90picross
91#endif 91#endif
92
93#if (LCD_DEPTH > 1)
94xrick
95#endif
diff --git a/apps/plugins/xrick/3rd_party/miniz/miniz.c b/apps/plugins/xrick/3rd_party/miniz/miniz.c
new file mode 100644
index 0000000000..7c26f3b4ba
--- /dev/null
+++ b/apps/plugins/xrick/3rd_party/miniz/miniz.c
@@ -0,0 +1,4928 @@
1/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
2 See "unlicense" statement at the end of this file.
3 Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
4 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
5
6 Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
7 MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
8
9 * Change History
10 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!):
11 - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug
12 would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place()
13 (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag).
14 - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size
15 - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries.
16 Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice).
17 - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes
18 - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
19 - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6.
20 - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
21 - Merged MZ_FORCEINLINE fix from hdeanclark
22 - Fix <time.h> include before config #ifdef, thanks emil.brink
23 - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can
24 set it to 1 for real-time compression).
25 - Merged in some compiler fixes from paulharris's github repro.
26 - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3.
27 - Added example6.c, which dumps an image of the mandelbrot set to a PNG file.
28 - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
29 - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled
30 - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch
31 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
32 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
33 - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files.
34 - Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
35 - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly
36 "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
37 - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64.
38 - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test.
39 - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives.
40 - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.)
41 - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself).
42 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's.
43 level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report.
44 5/28/11 v1.11 - Added statement from unlicense.org
45 5/27/11 v1.10 - Substantial compressor optimizations:
46 - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a
47 - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86).
48 - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types.
49 - Refactored the compression code for better readability and maintainability.
50 - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large
51 drop in throughput on some files).
52 5/15/11 v1.09 - Initial stable release.
53
54 * Low-level Deflate/Inflate implementation notes:
55
56 Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
57 greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
58 approximately as well as zlib.
59
60 Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
61 coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
62 block large enough to hold the entire file.
63
64 The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.
65
66 * zlib-style API notes:
67
68 miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
69 zlib replacement in many apps:
70 The z_stream struct, optional memory allocation callbacks
71 deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
72 inflateInit/inflateInit2/inflate/inflateEnd
73 compress, compress2, compressBound, uncompress
74 CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
75 Supports raw deflate streams or standard zlib streams with adler-32 checking.
76
77 Limitations:
78 The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
79 I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
80 there are no guarantees that miniz.c pulls this off perfectly.
81
82 * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
83 Alex Evans. Supports 1-4 bytes/pixel images.
84
85 * ZIP archive API notes:
86
87 The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
88 get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
89 existing archives, create new archives, append new files to existing archives, or clone archive data from
90 one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
91 or you can specify custom file read/write callbacks.
92
93 - Archive reading: Just call this function to read a single file from a disk archive:
94
95 void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
96 size_t *pSize, mz_uint zip_flags);
97
98 For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
99 directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.
100
101 - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:
102
103 int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
104
105 The locate operation can optionally check file comments too, which (as one example) can be used to identify
106 multiple versions of the same file in an archive. This function uses a simple linear search through the central
107 directory, so it's not very fast.
108
109 Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
110 retrieve detailed info on each file by calling mz_zip_reader_file_stat().
111
112 - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
113 to disk and builds an exact image of the central directory in memory. The central directory image is written
114 all at once at the end of the archive file when the archive is finalized.
115
116 The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
117 which can be useful when the archive will be read from optical media. Also, the writer supports placing
118 arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
119 readable by any ZIP tool.
120
121 - Archive appending: The simple way to add a single file to an archive is to call this function:
122
123 mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,
124 const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
125
126 The archive will be created if it doesn't already exist, otherwise it'll be appended to.
127 Note the appending is done in-place and is not an atomic operation, so if something goes wrong
128 during the operation it's possible the archive could be left without a central directory (although the local
129 file headers and file data will be fine, so the archive will be recoverable).
130
131 For more complex archive modification scenarios:
132 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
133 preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
134 compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
135 you're done. This is safe but requires a bunch of temporary disk space or heap memory.
136
137 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
138 append new files as needed, then finalize the archive which will write an updated central directory to the
139 original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
140 possibility that the archive's central directory could be lost with this method if anything goes wrong, though.
141
142 - ZIP archive support limitations:
143 No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
144 Requires streams capable of seeking.
145
146 * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
147 below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
148
149 * Important: For best perf. be sure to customize the below macros for your target platform:
150 #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
151 #define MINIZ_LITTLE_ENDIAN 1
152 #define MINIZ_HAS_64BIT_REGISTERS 1
153
154 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz
155 uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files
156 (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
157*/
158
159#ifndef MINIZ_HEADER_INCLUDED
160#define MINIZ_HEADER_INCLUDED
161
162#include <stdlib.h>
163
164// Defines to completely disable specific portions of miniz.c:
165// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl.
166
167// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O.
168//#define MINIZ_NO_STDIO
169
170// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or
171// get/set file times, and the C run-time funcs that get/set times won't be called.
172// The current downside is the times written to your archives will be from 1979.
173//#define MINIZ_NO_TIME
174
175// Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's.
176//#define MINIZ_NO_ARCHIVE_APIS
177
178// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's.
179//#define MINIZ_NO_ARCHIVE_WRITING_APIS
180
181// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
182//#define MINIZ_NO_ZLIB_APIS
183
184// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
185//#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
186
187// Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc.
188// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
189// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
190// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work.
191//#define MINIZ_NO_MALLOC
192
193#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
194 // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux
195 #define MINIZ_NO_TIME
196#endif
197
198#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
199 #include <time.h>
200#endif
201
202#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
203// MINIZ_X86_OR_X64_CPU is only used to help set the below macros.
204#define MINIZ_X86_OR_X64_CPU 1
205#endif
206
207#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
208// Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian.
209#define MINIZ_LITTLE_ENDIAN 1
210#endif
211
212#if MINIZ_X86_OR_X64_CPU
213// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses.
214#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
215#endif
216
217#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
218// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions).
219#define MINIZ_HAS_64BIT_REGISTERS 1
220#endif
221
222#ifdef __cplusplus
223extern "C" {
224#endif
225
226// ------------------- zlib-style API Definitions.
227
228// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits!
229typedef unsigned long mz_ulong;
230
231// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap.
232void mz_free(void *p);
233
234#define MZ_ADLER32_INIT (1)
235// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL.
236mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
237
238#define MZ_CRC32_INIT (0)
239// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL.
240mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
241
242// Compression strategies.
243enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 };
244
245// Method
246#define MZ_DEFLATED 8
247
248#ifndef MINIZ_NO_ZLIB_APIS
249
250// Heap allocation callbacks.
251// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long.
252typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
253typedef void (*mz_free_func)(void *opaque, void *address);
254typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
255
256#define MZ_VERSION "9.1.15"
257#define MZ_VERNUM 0x91F0
258#define MZ_VER_MAJOR 9
259#define MZ_VER_MINOR 1
260#define MZ_VER_REVISION 15
261#define MZ_VER_SUBREVISION 0
262
263// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs).
264enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 };
265
266// Return status codes. MZ_PARAM_ERROR is non-standard.
267enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
268
269// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL.
270enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 };
271
272// Window bits
273#define MZ_DEFAULT_WINDOW_BITS 15
274
275struct mz_internal_state;
276
277// Compression/decompression stream struct.
278typedef struct mz_stream_s
279{
280 const unsigned char *next_in; // pointer to next byte to read
281 unsigned int avail_in; // number of bytes available at next_in
282 mz_ulong total_in; // total number of bytes consumed so far
283
284 unsigned char *next_out; // pointer to next byte to write
285 unsigned int avail_out; // number of bytes that can be written to next_out
286 mz_ulong total_out; // total number of bytes produced so far
287
288 char *msg; // error msg (unused)
289 struct mz_internal_state *state; // internal state, allocated by zalloc/zfree
290
291 mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc)
292 mz_free_func zfree; // optional heap free function (defaults to free)
293 void *opaque; // heap alloc function user pointer
294
295 int data_type; // data_type (unused)
296 mz_ulong adler; // adler32 of the source or uncompressed data
297 mz_ulong reserved; // not used
298} mz_stream;
299
300typedef mz_stream *mz_streamp;
301
302// Returns the version string of miniz.c.
303const char *mz_version(void);
304
305// mz_deflateInit() initializes a compressor with default options:
306// Parameters:
307// pStream must point to an initialized mz_stream struct.
308// level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION].
309// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio.
310// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.)
311// Return values:
312// MZ_OK on success.
313// MZ_STREAM_ERROR if the stream is bogus.
314// MZ_PARAM_ERROR if the input parameters are bogus.
315// MZ_MEM_ERROR on out of memory.
316int mz_deflateInit(mz_streamp pStream, int level);
317
318// mz_deflateInit2() is like mz_deflate(), except with more control:
319// Additional parameters:
320// method must be MZ_DEFLATED
321// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer)
322// mem_level must be between [1, 9] (it's checked but ignored by miniz.c)
323int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);
324
325// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2().
326int mz_deflateReset(mz_streamp pStream);
327
328// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible.
329// Parameters:
330// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
331// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH.
332// Return values:
333// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full).
334// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore.
335// MZ_STREAM_ERROR if the stream is bogus.
336// MZ_PARAM_ERROR if one of the parameters is invalid.
337// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.)
338int mz_deflate(mz_streamp pStream, int flush);
339
340// mz_deflateEnd() deinitializes a compressor:
341// Return values:
342// MZ_OK on success.
343// MZ_STREAM_ERROR if the stream is bogus.
344int mz_deflateEnd(mz_streamp pStream);
345
346// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH.
347mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
348
349// Single-call compression functions mz_compress() and mz_compress2():
350// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure.
351int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
352int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
353
354// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress().
355mz_ulong mz_compressBound(mz_ulong source_len);
356
357// Initializes a decompressor.
358int mz_inflateInit(mz_streamp pStream);
359
360// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer:
361// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate).
362int mz_inflateInit2(mz_streamp pStream, int window_bits);
363
364// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible.
365// Parameters:
366// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members.
367// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH.
368// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster).
369// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data.
370// Return values:
371// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full.
372// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified.
373// MZ_STREAM_ERROR if the stream is bogus.
374// MZ_DATA_ERROR if the deflate stream is invalid.
375// MZ_PARAM_ERROR if one of the parameters is invalid.
376// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again
377// with more input data, or with more room in the output buffer (except when using single call decompression, described above).
378int mz_inflate(mz_streamp pStream, int flush);
379
380// Deinitializes a decompressor.
381int mz_inflateEnd(mz_streamp pStream);
382
383// Single-call decompression.
384// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure.
385int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
386
387// Returns a string description of the specified error code, or NULL if the error code is invalid.
388const char *mz_error(int err);
389
390// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports.
391// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project.
392#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
393 typedef unsigned char Byte;
394 typedef unsigned int uInt;
395 typedef mz_ulong uLong;
396 typedef Byte Bytef;
397 typedef uInt uIntf;
398 typedef char charf;
399 typedef int intf;
400 typedef void *voidpf;
401 typedef uLong uLongf;
402 typedef void *voidp;
403 typedef void *const voidpc;
404 #define Z_NULL 0
405 #define Z_NO_FLUSH MZ_NO_FLUSH
406 #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
407 #define Z_SYNC_FLUSH MZ_SYNC_FLUSH
408 #define Z_FULL_FLUSH MZ_FULL_FLUSH
409 #define Z_FINISH MZ_FINISH
410 #define Z_BLOCK MZ_BLOCK
411 #define Z_OK MZ_OK
412 #define Z_STREAM_END MZ_STREAM_END
413 #define Z_NEED_DICT MZ_NEED_DICT
414 #define Z_ERRNO MZ_ERRNO
415 #define Z_STREAM_ERROR MZ_STREAM_ERROR
416 #define Z_DATA_ERROR MZ_DATA_ERROR
417 #define Z_MEM_ERROR MZ_MEM_ERROR
418 #define Z_BUF_ERROR MZ_BUF_ERROR
419 #define Z_VERSION_ERROR MZ_VERSION_ERROR
420 #define Z_PARAM_ERROR MZ_PARAM_ERROR
421 #define Z_NO_COMPRESSION MZ_NO_COMPRESSION
422 #define Z_BEST_SPEED MZ_BEST_SPEED
423 #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
424 #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
425 #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
426 #define Z_FILTERED MZ_FILTERED
427 #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
428 #define Z_RLE MZ_RLE
429 #define Z_FIXED MZ_FIXED
430 #define Z_DEFLATED MZ_DEFLATED
431 #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
432 #define alloc_func mz_alloc_func
433 #define free_func mz_free_func
434 #define internal_state mz_internal_state
435 #define z_stream mz_stream
436 #define deflateInit mz_deflateInit
437 #define deflateInit2 mz_deflateInit2
438 #define deflateReset mz_deflateReset
439 #define deflate mz_deflate
440 #define deflateEnd mz_deflateEnd
441 #define deflateBound mz_deflateBound
442 #define compress mz_compress
443 #define compress2 mz_compress2
444 #define compressBound mz_compressBound
445 #define inflateInit mz_inflateInit
446 #define inflateInit2 mz_inflateInit2
447 #define inflate mz_inflate
448 #define inflateEnd mz_inflateEnd
449 #define uncompress mz_uncompress
450 #define crc32 mz_crc32
451 #define adler32 mz_adler32
452 #define MAX_WBITS 15
453 #define MAX_MEM_LEVEL 9
454 #define zError mz_error
455 #define ZLIB_VERSION MZ_VERSION
456 #define ZLIB_VERNUM MZ_VERNUM
457 #define ZLIB_VER_MAJOR MZ_VER_MAJOR
458 #define ZLIB_VER_MINOR MZ_VER_MINOR
459 #define ZLIB_VER_REVISION MZ_VER_REVISION
460 #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
461 #define zlibVersion mz_version
462 #define zlib_version mz_version()
463#endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
464
465#endif // MINIZ_NO_ZLIB_APIS
466
467// ------------------- Types and macros
468
469typedef unsigned char mz_uint8;
470typedef signed short mz_int16;
471typedef unsigned short mz_uint16;
472typedef unsigned int mz_uint32;
473typedef unsigned int mz_uint;
474typedef long long mz_int64;
475typedef unsigned long long mz_uint64;
476typedef int mz_bool;
477
478#define MZ_FALSE (0)
479#define MZ_TRUE (1)
480
481// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message.
482#ifdef _MSC_VER
483 #define MZ_MACRO_END while (0, 0)
484#else
485 #define MZ_MACRO_END while (0)
486#endif
487
488// ------------------- ZIP archive reading/writing
489
490#ifndef MINIZ_NO_ARCHIVE_APIS
491
492enum
493{
494 MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024,
495 MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
496 MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
497};
498
499typedef struct
500{
501 mz_uint32 m_file_index;
502 mz_uint32 m_central_dir_ofs;
503 mz_uint16 m_version_made_by;
504 mz_uint16 m_version_needed;
505 mz_uint16 m_bit_flag;
506 mz_uint16 m_method;
507#ifndef MINIZ_NO_TIME
508 time_t m_time;
509#endif
510 mz_uint32 m_crc32;
511 mz_uint64 m_comp_size;
512 mz_uint64 m_uncomp_size;
513 mz_uint16 m_internal_attr;
514 mz_uint32 m_external_attr;
515 mz_uint64 m_local_header_ofs;
516 mz_uint32 m_comment_size;
517 char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
518 char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
519} mz_zip_archive_file_stat;
520
521typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
522typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
523
524struct mz_zip_internal_state_tag;
525typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
526
527typedef enum
528{
529 MZ_ZIP_MODE_INVALID = 0,
530 MZ_ZIP_MODE_READING = 1,
531 MZ_ZIP_MODE_WRITING = 2,
532 MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
533} mz_zip_mode;
534
535typedef struct mz_zip_archive_tag
536{
537 mz_uint64 m_archive_size;
538 mz_uint64 m_central_directory_file_ofs;
539 mz_uint m_total_files;
540 mz_zip_mode m_zip_mode;
541
542 mz_uint m_file_offset_alignment;
543
544 mz_alloc_func m_pAlloc;
545 mz_free_func m_pFree;
546 mz_realloc_func m_pRealloc;
547 void *m_pAlloc_opaque;
548
549 mz_file_read_func m_pRead;
550 mz_file_write_func m_pWrite;
551 void *m_pIO_opaque;
552
553 mz_zip_internal_state *m_pState;
554
555} mz_zip_archive;
556
557typedef enum
558{
559 MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
560 MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
561 MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
562 MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
563} mz_zip_flags;
564
565// ZIP archive reading
566
567// Inits a ZIP archive reader.
568// These functions read and validate the archive's central directory.
569mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags);
570mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags);
571
572#ifndef MINIZ_NO_STDIO
573mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
574#endif
575
576// Returns the total number of files in the archive.
577mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
578
579// Returns detailed information about an archive file entry.
580mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);
581
582// Determines if an archive file entry is a directory entry.
583mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
584mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);
585
586// Retrieves the filename of an archive file entry.
587// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename.
588mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
589
590// Attempts to locates a file in the archive's central directory.
591// Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH
592// Returns -1 if the file cannot be found.
593int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
594
595// Extracts a archive file to a memory buffer using no memory allocation.
596mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
597mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
598
599// Extracts a archive file to a memory buffer.
600mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);
601mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);
602
603// Extracts a archive file to a dynamically allocated heap buffer.
604void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
605void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);
606
607// Extracts a archive file using a callback function to output the file's data.
608mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
609mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
610
611#ifndef MINIZ_NO_STDIO
612// Extracts a archive file to a disk file and sets its last accessed and modified times.
613// This function only extracts files, not archive directory records.
614mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
615mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);
616#endif
617
618// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used.
619mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
620
621// ZIP archive writing
622
623#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
624
625// Inits a ZIP archive writer.
626mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
627mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
628
629#ifndef MINIZ_NO_STDIO
630mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
631#endif
632
633// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive.
634// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called.
635// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it).
636// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL.
637// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before
638// the archive is finalized the file's central directory will be hosed.
639mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
640
641// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive.
642// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer.
643// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
644mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);
645mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
646
647#ifndef MINIZ_NO_STDIO
648// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive.
649// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
650mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
651#endif
652
653// Adds a file to an archive by fully cloning the data from another archive.
654// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields.
655mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index);
656
657// Finalizes the archive by writing the central directory records followed by the end of central directory record.
658// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end().
659// An archive must be manually finalized by calling this function for it to be valid.
660mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
661mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize);
662
663// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used.
664// Note for the archive to be valid, it must have been finalized before ending.
665mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
666
667// Misc. high-level helper functions:
668
669// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive.
670// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION.
671mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
672
673// Reads a single file from an archive into a heap block.
674// Returns NULL on failure.
675void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags);
676
677#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
678
679#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
680
681// ------------------- Low-level Decompression API Definitions
682
683// Decompression flags used by tinfl_decompress().
684// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream.
685// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input.
686// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB).
687// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes.
688enum
689{
690 TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
691 TINFL_FLAG_HAS_MORE_INPUT = 2,
692 TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
693 TINFL_FLAG_COMPUTE_ADLER32 = 8
694};
695
696// High level decompression functions:
697// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc().
698// On entry:
699// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress.
700// On return:
701// Function returns a pointer to the decompressed data, or NULL on failure.
702// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data.
703// The caller must call mz_free() on the returned block when it's no longer needed.
704void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
705
706// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory.
707// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success.
708#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
709size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
710
711// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer.
712// Returns 1 on success or 0 on failure.
713typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
714int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
715
716struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor;
717
718// Max size of LZ dictionary.
719#define TINFL_LZ_DICT_SIZE 32768
720
721// Return status.
722typedef enum
723{
724 TINFL_STATUS_BAD_PARAM = -3,
725 TINFL_STATUS_ADLER32_MISMATCH = -2,
726 TINFL_STATUS_FAILED = -1,
727 TINFL_STATUS_DONE = 0,
728 TINFL_STATUS_NEEDS_MORE_INPUT = 1,
729 TINFL_STATUS_HAS_MORE_OUTPUT = 2
730} tinfl_status;
731
732// Initializes the decompressor to its initial state.
733#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END
734#define tinfl_get_adler32(r) (r)->m_check_adler32
735
736// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability.
737// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output.
738tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
739
740// Internal/private bits follow.
741enum
742{
743 TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19,
744 TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
745};
746
747typedef struct
748{
749 mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
750 mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
751} tinfl_huff_table;
752
753#if MINIZ_HAS_64BIT_REGISTERS
754 #define TINFL_USE_64BIT_BITBUF 1
755#endif
756
757#if TINFL_USE_64BIT_BITBUF
758 typedef mz_uint64 tinfl_bit_buf_t;
759 #define TINFL_BITBUF_SIZE (64)
760#else
761 typedef mz_uint32 tinfl_bit_buf_t;
762 #define TINFL_BITBUF_SIZE (32)
763#endif
764
765struct tinfl_decompressor_tag
766{
767 mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
768 tinfl_bit_buf_t m_bit_buf;
769 size_t m_dist_from_out_buf_start;
770 tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
771 mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
772};
773
774// ------------------- Low-level Compression API Definitions
775
776// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently).
777#define TDEFL_LESS_MEMORY 0
778
779// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search):
780// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression).
781enum
782{
783 TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF
784};
785
786// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data.
787// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers).
788// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing.
789// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory).
790// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1)
791// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled.
792// TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables.
793// TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks.
794// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK).
795enum
796{
797 TDEFL_WRITE_ZLIB_HEADER = 0x01000,
798 TDEFL_COMPUTE_ADLER32 = 0x02000,
799 TDEFL_GREEDY_PARSING_FLAG = 0x04000,
800 TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
801 TDEFL_RLE_MATCHES = 0x10000,
802 TDEFL_FILTER_MATCHES = 0x20000,
803 TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
804 TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
805};
806
807// High level compression functions:
808// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc().
809// On entry:
810// pSrc_buf, src_buf_len: Pointer and size of source block to compress.
811// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression.
812// On return:
813// Function returns a pointer to the compressed data, or NULL on failure.
814// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data.
815// The caller must free() the returned block when it's no longer needed.
816void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
817
818// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory.
819// Returns 0 on failure.
820size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
821
822// Compresses an image to a compressed PNG file in memory.
823// On entry:
824// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4.
825// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory.
826// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL
827// If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps).
828// On return:
829// Function returns a pointer to the compressed data, or NULL on failure.
830// *pLen_out will be set to the size of the PNG image file.
831// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed.
832void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);
833void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);
834
835// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time.
836typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser);
837
838// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally.
839mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
840
841enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 };
842
843// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes).
844#if TDEFL_LESS_MEMORY
845enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
846#else
847enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS };
848#endif
849
850// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions.
851typedef enum
852{
853 TDEFL_STATUS_BAD_PARAM = -2,
854 TDEFL_STATUS_PUT_BUF_FAILED = -1,
855 TDEFL_STATUS_OKAY = 0,
856 TDEFL_STATUS_DONE = 1,
857} tdefl_status;
858
859// Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums
860typedef enum
861{
862 TDEFL_NO_FLUSH = 0,
863 TDEFL_SYNC_FLUSH = 2,
864 TDEFL_FULL_FLUSH = 3,
865 TDEFL_FINISH = 4
866} tdefl_flush;
867
868// tdefl's compression state structure.
869typedef struct
870{
871 tdefl_put_buf_func_ptr m_pPut_buf_func;
872 void *m_pPut_buf_user;
873 mz_uint m_flags, m_max_probes[2];
874 int m_greedy_parsing;
875 mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
876 mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
877 mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
878 mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
879 tdefl_status m_prev_return_status;
880 const void *m_pIn_buf;
881 void *m_pOut_buf;
882 size_t *m_pIn_buf_size, *m_pOut_buf_size;
883 tdefl_flush m_flush;
884 const mz_uint8 *m_pSrc;
885 size_t m_src_buf_left, m_out_buf_ofs;
886 mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
887 mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
888 mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
889 mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
890 mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
891 mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
892 mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
893 mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
894} tdefl_compressor;
895
896// Initializes the compressor.
897// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory.
898// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression.
899// If pBut_buf_func is NULL the user should always call the tdefl_compress() API.
900// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.)
901tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
902
903// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible.
904tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
905
906// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr.
907// tdefl_compress_buffer() always consumes the entire input buffer.
908tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
909
910tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
911mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
912
913// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros.
914#ifndef MINIZ_NO_ZLIB_APIS
915// Create tdefl_compress() flags given zlib-style compression parameters.
916// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files)
917// window_bits may be -15 (raw deflate) or 15 (zlib)
918// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED
919mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
920#endif // #ifndef MINIZ_NO_ZLIB_APIS
921
922#ifdef __cplusplus
923}
924#endif
925
926#endif // MINIZ_HEADER_INCLUDED
927
928// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.)
929
930#ifndef MINIZ_HEADER_FILE_ONLY
931
932typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1];
933typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1];
934typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1];
935
936#include <string.h>
937
938#ifdef MINIZ_NO_ASSERT
939 #define MZ_ASSERT(x)
940#else
941 #include <assert.h>
942 #define MZ_ASSERT(x) assert(x)
943#endif
944
945#ifdef MINIZ_NO_MALLOC
946 #define MZ_MALLOC(x) NULL
947 #define MZ_FREE(x) (void)x, ((void)0)
948 #define MZ_REALLOC(p, x) NULL
949#else
950 #define MZ_MALLOC(x) malloc(x)
951 #define MZ_FREE(x) free(x)
952 #define MZ_REALLOC(p, x) realloc(p, x)
953#endif
954
955#define MZ_MAX(a,b) (((a)>(b))?(a):(b))
956#define MZ_MIN(a,b) (((a)<(b))?(a):(b))
957#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
958
959#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
960 #define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
961 #define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
962#else
963 #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
964 #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
965#endif
966
967#ifdef _MSC_VER
968 #define MZ_FORCEINLINE __forceinline
969#elif defined(__GNUC__)
970 #define MZ_FORCEINLINE inline __attribute__((__always_inline__))
971#else
972 #define MZ_FORCEINLINE inline
973#endif
974
975#ifdef __cplusplus
976 extern "C" {
977#endif
978
979// ------------------- zlib-style API's
980
981mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
982{
983 mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552;
984 if (!ptr) return MZ_ADLER32_INIT;
985 while (buf_len) {
986 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
987 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
988 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
989 }
990 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
991 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
992 }
993 return (s2 << 16) + s1;
994}
995
996// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/
997mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
998{
999 static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
1000 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
1001 mz_uint32 crcu32 = (mz_uint32)crc;
1002 if (!ptr) return MZ_CRC32_INIT;
1003 crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
1004 return ~crcu32;
1005}
1006
1007void mz_free(void *p)
1008{
1009 MZ_FREE(p);
1010}
1011
1012#ifndef MINIZ_NO_ZLIB_APIS
1013
1014static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); }
1015static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); }
1016static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); }
1017
1018const char *mz_version(void)
1019{
1020 return MZ_VERSION;
1021}
1022
1023int mz_deflateInit(mz_streamp pStream, int level)
1024{
1025 return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
1026}
1027
1028int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
1029{
1030 tdefl_compressor *pComp;
1031 mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
1032
1033 if (!pStream) return MZ_STREAM_ERROR;
1034 if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR;
1035
1036 pStream->data_type = 0;
1037 pStream->adler = MZ_ADLER32_INIT;
1038 pStream->msg = NULL;
1039 pStream->reserved = 0;
1040 pStream->total_in = 0;
1041 pStream->total_out = 0;
1042 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
1043 if (!pStream->zfree) pStream->zfree = def_free_func;
1044
1045 pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
1046 if (!pComp)
1047 return MZ_MEM_ERROR;
1048
1049 pStream->state = (struct mz_internal_state *)pComp;
1050
1051 if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
1052 {
1053 mz_deflateEnd(pStream);
1054 return MZ_PARAM_ERROR;
1055 }
1056
1057 return MZ_OK;
1058}
1059
1060int mz_deflateReset(mz_streamp pStream)
1061{
1062 if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR;
1063 pStream->total_in = pStream->total_out = 0;
1064 tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags);
1065 return MZ_OK;
1066}
1067
1068int mz_deflate(mz_streamp pStream, int flush)
1069{
1070 size_t in_bytes, out_bytes;
1071 mz_ulong orig_total_in, orig_total_out;
1072 int mz_status = MZ_OK;
1073
1074 if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR;
1075 if (!pStream->avail_out) return MZ_BUF_ERROR;
1076
1077 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
1078
1079 if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
1080 return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
1081
1082 orig_total_in = pStream->total_in; orig_total_out = pStream->total_out;
1083 for ( ; ; )
1084 {
1085 tdefl_status defl_status;
1086 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
1087
1088 defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
1089 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
1090 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state);
1091
1092 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes;
1093 pStream->total_out += (mz_uint)out_bytes;
1094
1095 if (defl_status < 0)
1096 {
1097 mz_status = MZ_STREAM_ERROR;
1098 break;
1099 }
1100 else if (defl_status == TDEFL_STATUS_DONE)
1101 {
1102 mz_status = MZ_STREAM_END;
1103 break;
1104 }
1105 else if (!pStream->avail_out)
1106 break;
1107 else if ((!pStream->avail_in) && (flush != MZ_FINISH))
1108 {
1109 if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
1110 break;
1111 return MZ_BUF_ERROR; // Can't make forward progress without some input.
1112 }
1113 }
1114 return mz_status;
1115}
1116
1117int mz_deflateEnd(mz_streamp pStream)
1118{
1119 if (!pStream) return MZ_STREAM_ERROR;
1120 if (pStream->state)
1121 {
1122 pStream->zfree(pStream->opaque, pStream->state);
1123 pStream->state = NULL;
1124 }
1125 return MZ_OK;
1126}
1127
1128mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
1129{
1130 (void)pStream;
1131 // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.)
1132 return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
1133}
1134
1135int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
1136{
1137 int status;
1138 mz_stream stream;
1139 memset(&stream, 0, sizeof(stream));
1140
1141 // In case mz_ulong is 64-bits (argh I hate longs).
1142 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
1143
1144 stream.next_in = pSource;
1145 stream.avail_in = (mz_uint32)source_len;
1146 stream.next_out = pDest;
1147 stream.avail_out = (mz_uint32)*pDest_len;
1148
1149 status = mz_deflateInit(&stream, level);
1150 if (status != MZ_OK) return status;
1151
1152 status = mz_deflate(&stream, MZ_FINISH);
1153 if (status != MZ_STREAM_END)
1154 {
1155 mz_deflateEnd(&stream);
1156 return (status == MZ_OK) ? MZ_BUF_ERROR : status;
1157 }
1158
1159 *pDest_len = stream.total_out;
1160 return mz_deflateEnd(&stream);
1161}
1162
1163int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
1164{
1165 return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
1166}
1167
1168mz_ulong mz_compressBound(mz_ulong source_len)
1169{
1170 return mz_deflateBound(NULL, source_len);
1171}
1172
1173typedef struct
1174{
1175 tinfl_decompressor m_decomp;
1176 mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits;
1177 mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
1178 tinfl_status m_last_status;
1179} inflate_state;
1180
1181int mz_inflateInit2(mz_streamp pStream, int window_bits)
1182{
1183 inflate_state *pDecomp;
1184 if (!pStream) return MZ_STREAM_ERROR;
1185 if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR;
1186
1187 pStream->data_type = 0;
1188 pStream->adler = 0;
1189 pStream->msg = NULL;
1190 pStream->total_in = 0;
1191 pStream->total_out = 0;
1192 pStream->reserved = 0;
1193 if (!pStream->zalloc) pStream->zalloc = def_alloc_func;
1194 if (!pStream->zfree) pStream->zfree = def_free_func;
1195
1196 pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
1197 if (!pDecomp) return MZ_MEM_ERROR;
1198
1199 pStream->state = (struct mz_internal_state *)pDecomp;
1200
1201 tinfl_init(&pDecomp->m_decomp);
1202 pDecomp->m_dict_ofs = 0;
1203 pDecomp->m_dict_avail = 0;
1204 pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
1205 pDecomp->m_first_call = 1;
1206 pDecomp->m_has_flushed = 0;
1207 pDecomp->m_window_bits = window_bits;
1208
1209 return MZ_OK;
1210}
1211
1212int mz_inflateInit(mz_streamp pStream)
1213{
1214 return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
1215}
1216
1217int mz_inflate(mz_streamp pStream, int flush)
1218{
1219 inflate_state* pState;
1220 mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
1221 size_t in_bytes, out_bytes, orig_avail_in;
1222 tinfl_status status;
1223
1224 if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR;
1225 if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH;
1226 if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
1227
1228 pState = (inflate_state*)pStream->state;
1229 if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
1230 orig_avail_in = pStream->avail_in;
1231
1232 first_call = pState->m_first_call; pState->m_first_call = 0;
1233 if (pState->m_last_status < 0) return MZ_DATA_ERROR;
1234
1235 if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR;
1236 pState->m_has_flushed |= (flush == MZ_FINISH);
1237
1238 if ((flush == MZ_FINISH) && (first_call))
1239 {
1240 // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file.
1241 decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
1242 in_bytes = pStream->avail_in; out_bytes = pStream->avail_out;
1243 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
1244 pState->m_last_status = status;
1245 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes;
1246 pStream->adler = tinfl_get_adler32(&pState->m_decomp);
1247 pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes;
1248
1249 if (status < 0)
1250 return MZ_DATA_ERROR;
1251 else if (status != TINFL_STATUS_DONE)
1252 {
1253 pState->m_last_status = TINFL_STATUS_FAILED;
1254 return MZ_BUF_ERROR;
1255 }
1256 return MZ_STREAM_END;
1257 }
1258 // flush != MZ_FINISH then we must assume there's more input.
1259 if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
1260
1261 if (pState->m_dict_avail)
1262 {
1263 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
1264 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
1265 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
1266 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
1267 return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
1268 }
1269
1270 for ( ; ; )
1271 {
1272 in_bytes = pStream->avail_in;
1273 out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
1274
1275 status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
1276 pState->m_last_status = status;
1277
1278 pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes;
1279 pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp);
1280
1281 pState->m_dict_avail = (mz_uint)out_bytes;
1282
1283 n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
1284 memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
1285 pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n;
1286 pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
1287
1288 if (status < 0)
1289 return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well).
1290 else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
1291 return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH.
1292 else if (flush == MZ_FINISH)
1293 {
1294 // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH.
1295 if (status == TINFL_STATUS_DONE)
1296 return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
1297 // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong.
1298 else if (!pStream->avail_out)
1299 return MZ_BUF_ERROR;
1300 }
1301 else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
1302 break;
1303 }
1304
1305 return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
1306}
1307
1308int mz_inflateEnd(mz_streamp pStream)
1309{
1310 if (!pStream)
1311 return MZ_STREAM_ERROR;
1312 if (pStream->state)
1313 {
1314 pStream->zfree(pStream->opaque, pStream->state);
1315 pStream->state = NULL;
1316 }
1317 return MZ_OK;
1318}
1319
1320int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
1321{
1322 mz_stream stream;
1323 int status;
1324 memset(&stream, 0, sizeof(stream));
1325
1326 // In case mz_ulong is 64-bits (argh I hate longs).
1327 if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR;
1328
1329 stream.next_in = pSource;
1330 stream.avail_in = (mz_uint32)source_len;
1331 stream.next_out = pDest;
1332 stream.avail_out = (mz_uint32)*pDest_len;
1333
1334 status = mz_inflateInit(&stream);
1335 if (status != MZ_OK)
1336 return status;
1337
1338 status = mz_inflate(&stream, MZ_FINISH);
1339 if (status != MZ_STREAM_END)
1340 {
1341 mz_inflateEnd(&stream);
1342 return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
1343 }
1344 *pDest_len = stream.total_out;
1345
1346 return mz_inflateEnd(&stream);
1347}
1348
1349const char *mz_error(int err)
1350{
1351 static struct { int m_err; const char *m_pDesc; } s_error_descs[] =
1352 {
1353 { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
1354 { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" }
1355 };
1356 mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc;
1357 return NULL;
1358}
1359
1360#endif //MINIZ_NO_ZLIB_APIS
1361
1362// ------------------- Low-level Decompression (completely independent from all compression API's)
1363
1364#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
1365#define TINFL_MEMSET(p, c, l) memset(p, c, l)
1366
1367#define TINFL_CR_BEGIN switch(r->m_state) { case 0:
1368#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END
1369#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END
1370#define TINFL_CR_FINISH }
1371
1372// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never
1373// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario.
1374#define TINFL_GET_BYTE(state_index, c) do { \
1375 if (pIn_buf_cur >= pIn_buf_end) { \
1376 for ( ; ; ) { \
1377 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \
1378 TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \
1379 if (pIn_buf_cur < pIn_buf_end) { \
1380 c = *pIn_buf_cur++; \
1381 break; \
1382 } \
1383 } else { \
1384 c = 0; \
1385 break; \
1386 } \
1387 } \
1388 } else c = *pIn_buf_cur++; } MZ_MACRO_END
1389
1390#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n))
1391#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
1392#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END
1393
1394// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2.
1395// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a
1396// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the
1397// bit buffer contains >=15 bits (deflate's max. Huffman code size).
1398#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
1399 do { \
1400 temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \
1401 if (temp >= 0) { \
1402 code_len = temp >> 9; \
1403 if ((code_len) && (num_bits >= code_len)) \
1404 break; \
1405 } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \
1406 code_len = TINFL_FAST_LOOKUP_BITS; \
1407 do { \
1408 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
1409 } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
1410 } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
1411 } while (num_bits < 15);
1412
1413// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read
1414// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully
1415// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32.
1416// The slow path is only executed at the very end of the input buffer.
1417#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
1418 int temp; mz_uint code_len, c; \
1419 if (num_bits < 15) { \
1420 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
1421 TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
1422 } else { \
1423 bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
1424 } \
1425 } \
1426 if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
1427 code_len = temp >> 9, temp &= 511; \
1428 else { \
1429 code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
1430 } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END
1431
1432tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
1433{
1434 static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
1435 static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
1436 static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
1437 static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
1438 static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
1439 static const int s_min_table_sizes[3] = { 257, 1, 4 };
1440
1441 tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf;
1442 const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
1443 mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
1444 size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
1445
1446 // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter).
1447 if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; }
1448
1449 num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
1450 TINFL_CR_BEGIN
1451
1452 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
1453 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
1454 {
1455 TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1);
1456 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
1457 if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
1458 if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); }
1459 }
1460
1461 do
1462 {
1463 TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
1464 if (r->m_type == 0)
1465 {
1466 TINFL_SKIP_BITS(5, num_bits & 7);
1467 for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
1468 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); }
1469 while ((counter) && (num_bits))
1470 {
1471 TINFL_GET_BITS(51, dist, 8);
1472 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); }
1473 *pOut_buf_cur++ = (mz_uint8)dist;
1474 counter--;
1475 }
1476 while (counter)
1477 {
1478 size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); }
1479 while (pIn_buf_cur >= pIn_buf_end)
1480 {
1481 if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT)
1482 {
1483 TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT);
1484 }
1485 else
1486 {
1487 TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED);
1488 }
1489 }
1490 n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
1491 TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n;
1492 }
1493 }
1494 else if (r->m_type == 3)
1495 {
1496 TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
1497 }
1498 else
1499 {
1500 if (r->m_type == 1)
1501 {
1502 mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i;
1503 r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
1504 for ( i = 0; i <= 143; ++i) *p++ = 8;
1505 for ( ; i <= 255; ++i) *p++ = 9;
1506 for ( ; i <= 279; ++i) *p++ = 7;
1507 for ( ; i <= 287; ++i) *p++ = 8;
1508 }
1509 else
1510 {
1511 for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
1512 MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; }
1513 r->m_table_sizes[2] = 19;
1514 }
1515 for ( ; (int)r->m_type >= 0; r->m_type--)
1516 {
1517 int tree_next, tree_cur; tinfl_huff_table *pTable;
1518 mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree);
1519 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
1520 used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
1521 for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
1522 if ((65536 != total) && (used_syms > 1))
1523 {
1524 TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
1525 }
1526 for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
1527 {
1528 mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue;
1529 cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
1530 if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; }
1531 if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
1532 rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
1533 for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
1534 {
1535 tree_cur -= ((rev_code >>= 1) & 1);
1536 if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1];
1537 }
1538 tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
1539 }
1540 if (r->m_type == 2)
1541 {
1542 for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
1543 {
1544 mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; }
1545 if ((dist == 16) && (!counter))
1546 {
1547 TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
1548 }
1549 num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16];
1550 TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s;
1551 }
1552 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
1553 {
1554 TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
1555 }
1556 TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
1557 }
1558 }
1559 for ( ; ; )
1560 {
1561 mz_uint8 *pSrc;
1562 for ( ; ; )
1563 {
1564 if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
1565 {
1566 TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
1567 if (counter >= 256)
1568 break;
1569 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); }
1570 *pOut_buf_cur++ = (mz_uint8)counter;
1571 }
1572 else
1573 {
1574 int sym2; mz_uint code_len;
1575#if TINFL_USE_64BIT_BITBUF
1576 if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
1577#else
1578 if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
1579#endif
1580 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
1581 code_len = sym2 >> 9;
1582 else
1583 {
1584 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
1585 }
1586 counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
1587 if (counter & 256)
1588 break;
1589
1590#if !TINFL_USE_64BIT_BITBUF
1591 if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
1592#endif
1593 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
1594 code_len = sym2 >> 9;
1595 else
1596 {
1597 code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0);
1598 }
1599 bit_buf >>= code_len; num_bits -= code_len;
1600
1601 pOut_buf_cur[0] = (mz_uint8)counter;
1602 if (sym2 & 256)
1603 {
1604 pOut_buf_cur++;
1605 counter = sym2;
1606 break;
1607 }
1608 pOut_buf_cur[1] = (mz_uint8)sym2;
1609 pOut_buf_cur += 2;
1610 }
1611 }
1612 if ((counter &= 511) == 256) break;
1613
1614 num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
1615 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
1616
1617 TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
1618 num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
1619 if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
1620
1621 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
1622 if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
1623 {
1624 TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
1625 }
1626
1627 pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
1628
1629 if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
1630 {
1631 while (counter--)
1632 {
1633 while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); }
1634 *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
1635 }
1636 continue;
1637 }
1638#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
1639 else if ((counter >= 9) && (counter <= dist))
1640 {
1641 const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
1642 do
1643 {
1644 ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
1645 ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
1646 pOut_buf_cur += 8;
1647 } while ((pSrc += 8) < pSrc_end);
1648 if ((counter &= 7) < 3)
1649 {
1650 if (counter)
1651 {
1652 pOut_buf_cur[0] = pSrc[0];
1653 if (counter > 1)
1654 pOut_buf_cur[1] = pSrc[1];
1655 pOut_buf_cur += counter;
1656 }
1657 continue;
1658 }
1659 }
1660#endif
1661 do
1662 {
1663 pOut_buf_cur[0] = pSrc[0];
1664 pOut_buf_cur[1] = pSrc[1];
1665 pOut_buf_cur[2] = pSrc[2];
1666 pOut_buf_cur += 3; pSrc += 3;
1667 } while ((int)(counter -= 3) > 2);
1668 if ((int)counter > 0)
1669 {
1670 pOut_buf_cur[0] = pSrc[0];
1671 if ((int)counter > 1)
1672 pOut_buf_cur[1] = pSrc[1];
1673 pOut_buf_cur += counter;
1674 }
1675 }
1676 }
1677 } while (!(r->m_final & 1));
1678 if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
1679 {
1680 TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
1681 }
1682 TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
1683 TINFL_CR_FINISH
1684
1685common_exit:
1686 r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
1687 *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
1688 if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
1689 {
1690 const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size;
1691 mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552;
1692 while (buf_len)
1693 {
1694 for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
1695 {
1696 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
1697 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
1698 }
1699 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
1700 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
1701 }
1702 r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH;
1703 }
1704 return status;
1705}
1706
1707// Higher level helper functions.
1708void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
1709{
1710 tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0;
1711 *pOut_len = 0;
1712 tinfl_init(&decomp);
1713 for ( ; ; )
1714 {
1715 size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
1716 tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size,
1717 (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
1718 if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
1719 {
1720 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
1721 }
1722 src_buf_ofs += src_buf_size;
1723 *pOut_len += dst_buf_size;
1724 if (status == TINFL_STATUS_DONE) break;
1725 new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
1726 pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
1727 if (!pNew_buf)
1728 {
1729 MZ_FREE(pBuf); *pOut_len = 0; return NULL;
1730 }
1731 pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
1732 }
1733 return pBuf;
1734}
1735
1736size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
1737{
1738 tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp);
1739 status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
1740 return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
1741}
1742
1743int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
1744{
1745 int result = 0;
1746 tinfl_decompressor decomp;
1747 mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0;
1748 if (!pDict)
1749 return TINFL_STATUS_FAILED;
1750 tinfl_init(&decomp);
1751 for ( ; ; )
1752 {
1753 size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
1754 tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
1755 (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
1756 in_buf_ofs += in_buf_size;
1757 if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
1758 break;
1759 if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
1760 {
1761 result = (status == TINFL_STATUS_DONE);
1762 break;
1763 }
1764 dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
1765 }
1766 MZ_FREE(pDict);
1767 *pIn_buf_size = in_buf_ofs;
1768 return result;
1769}
1770
1771// ------------------- Low-level Compression (independent from all decompression API's)
1772
1773// Purposely making these tables static for faster init and thread safety.
1774static const mz_uint16 s_tdefl_len_sym[256] = {
1775 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272,
1776 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276,
1777 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,
1778 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,
1779 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,
1780 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,
1781 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,
1782 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 };
1783
1784static const mz_uint8 s_tdefl_len_extra[256] = {
1785 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
1786 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
1787 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
1788 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 };
1789
1790static const mz_uint8 s_tdefl_small_dist_sym[512] = {
1791 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,
1792 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,
1793 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,
1794 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
1795 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
1796 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,
1797 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
1798 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
1799 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
1800 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
1801 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
1802 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 };
1803
1804static const mz_uint8 s_tdefl_small_dist_extra[512] = {
1805 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
1806 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1807 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
1808 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1809 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1810 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1811 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
1812 7,7,7,7,7,7,7,7 };
1813
1814static const mz_uint8 s_tdefl_large_dist_sym[128] = {
1815 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,
1816 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,
1817 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 };
1818
1819static const mz_uint8 s_tdefl_large_dist_extra[128] = {
1820 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,
1821 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
1822 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 };
1823
1824// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values.
1825typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq;
1826static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1)
1827{
1828 mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist);
1829 for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; }
1830 while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--;
1831 for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
1832 {
1833 const mz_uint32* pHist = &hist[pass << 8];
1834 mz_uint offsets[256], cur_ofs = 0;
1835 for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; }
1836 for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
1837 { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; }
1838 }
1839 return pCur_syms;
1840}
1841
1842// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996.
1843static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
1844{
1845 int root, leaf, next, avbl, used, dpth;
1846 if (n==0) return; else if (n==1) { A[0].m_key = 1; return; }
1847 A[0].m_key += A[1].m_key; root = 0; leaf = 2;
1848 for (next=1; next < n-1; next++)
1849 {
1850 if (leaf>=n || A[root].m_key<A[leaf].m_key) { A[next].m_key = A[root].m_key; A[root++].m_key = (mz_uint16)next; } else A[next].m_key = A[leaf++].m_key;
1851 if (leaf>=n || (root<next && A[root].m_key<A[leaf].m_key)) { A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); A[root++].m_key = (mz_uint16)next; } else A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
1852 }
1853 A[n-2].m_key = 0; for (next=n-3; next>=0; next--) A[next].m_key = A[A[next].m_key].m_key+1;
1854 avbl = 1; used = dpth = 0; root = n-2; next = n-1;
1855 while (avbl>0)
1856 {
1857 while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; }
1858 while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; }
1859 avbl = 2*used; dpth++; used = 0;
1860 }
1861}
1862
1863// Limits canonical Huffman code table's max code size.
1864enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 };
1865static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
1866{
1867 int i; mz_uint32 total = 0; if (code_list_len <= 1) return;
1868 for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i];
1869 for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
1870 while (total != (1UL << max_code_size))
1871 {
1872 pNum_codes[max_code_size]--;
1873 for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; }
1874 total--;
1875 }
1876}
1877
1878static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
1879{
1880 int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes);
1881 if (static_table)
1882 {
1883 for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++;
1884 }
1885 else
1886 {
1887 tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
1888 int num_used_syms = 0;
1889 const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
1890 for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; }
1891
1892 pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
1893
1894 for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++;
1895
1896 tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
1897
1898 MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
1899 for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
1900 for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
1901 }
1902
1903 next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1);
1904
1905 for (i = 0; i < table_len; i++)
1906 {
1907 mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue;
1908 code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1);
1909 d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
1910 }
1911}
1912
1913#define TDEFL_PUT_BITS(b, l) do { \
1914 mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \
1915 d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \
1916 while (d->m_bits_in >= 8) { \
1917 if (d->m_pOutput_buf < d->m_pOutput_buf_end) \
1918 *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
1919 d->m_bit_buffer >>= 8; \
1920 d->m_bits_in -= 8; \
1921 } \
1922} MZ_MACRO_END
1923
1924#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \
1925 if (rle_repeat_count < 3) { \
1926 d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
1927 while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \
1928 } else { \
1929 d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \
1930} rle_repeat_count = 0; } }
1931
1932#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \
1933 if (rle_z_count < 3) { \
1934 d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \
1935 } else if (rle_z_count <= 10) { \
1936 d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \
1937 } else { \
1938 d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \
1939} rle_z_count = 0; } }
1940
1941static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
1942
1943static void tdefl_start_dynamic_block(tdefl_compressor *d)
1944{
1945 int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;
1946 mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF;
1947
1948 d->m_huff_count[0][256] = 1;
1949
1950 tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
1951 tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
1952
1953 for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break;
1954 for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break;
1955
1956 memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
1957 memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
1958 total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0;
1959
1960 memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
1961 for (i = 0; i < total_code_sizes_to_pack; i++)
1962 {
1963 mz_uint8 code_size = code_sizes_to_pack[i];
1964 if (!code_size)
1965 {
1966 TDEFL_RLE_PREV_CODE_SIZE();
1967 if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); }
1968 }
1969 else
1970 {
1971 TDEFL_RLE_ZERO_CODE_SIZE();
1972 if (code_size != prev_code_size)
1973 {
1974 TDEFL_RLE_PREV_CODE_SIZE();
1975 d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size;
1976 }
1977 else if (++rle_repeat_count == 6)
1978 {
1979 TDEFL_RLE_PREV_CODE_SIZE();
1980 }
1981 }
1982 prev_code_size = code_size;
1983 }
1984 if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); }
1985
1986 tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
1987
1988 TDEFL_PUT_BITS(2, 2);
1989
1990 TDEFL_PUT_BITS(num_lit_codes - 257, 5);
1991 TDEFL_PUT_BITS(num_dist_codes - 1, 5);
1992
1993 for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break;
1994 num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
1995 for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
1996
1997 for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; )
1998 {
1999 mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
2000 TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
2001 if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
2002 }
2003}
2004
2005static void tdefl_start_static_block(tdefl_compressor *d)
2006{
2007 mz_uint i;
2008 mz_uint8 *p = &d->m_huff_code_sizes[0][0];
2009
2010 for (i = 0; i <= 143; ++i) *p++ = 8;
2011 for ( ; i <= 255; ++i) *p++ = 9;
2012 for ( ; i <= 279; ++i) *p++ = 7;
2013 for ( ; i <= 287; ++i) *p++ = 8;
2014
2015 memset(d->m_huff_code_sizes[1], 5, 32);
2016
2017 tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
2018 tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
2019
2020 TDEFL_PUT_BITS(1, 2);
2021}
2022
2023static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
2024
2025#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
2026static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
2027{
2028 mz_uint flags;
2029 mz_uint8 *pLZ_codes;
2030 mz_uint8 *pOutput_buf = d->m_pOutput_buf;
2031 mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
2032 mz_uint64 bit_buffer = d->m_bit_buffer;
2033 mz_uint bits_in = d->m_bits_in;
2034
2035#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); }
2036
2037 flags = 1;
2038 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
2039 {
2040 if (flags == 1)
2041 flags = *pLZ_codes++ | 0x100;
2042
2043 if (flags & 1)
2044 {
2045 mz_uint s0, s1, n0, n1, sym, num_extra_bits;
2046 mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3;
2047
2048 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2049 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2050 TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
2051
2052 // This sequence coaxes MSVC into using cmov's vs. jmp's.
2053 s0 = s_tdefl_small_dist_sym[match_dist & 511];
2054 n0 = s_tdefl_small_dist_extra[match_dist & 511];
2055 s1 = s_tdefl_large_dist_sym[match_dist >> 8];
2056 n1 = s_tdefl_large_dist_extra[match_dist >> 8];
2057 sym = (match_dist < 512) ? s0 : s1;
2058 num_extra_bits = (match_dist < 512) ? n0 : n1;
2059
2060 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
2061 TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
2062 TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
2063 }
2064 else
2065 {
2066 mz_uint lit = *pLZ_codes++;
2067 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
2068 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
2069
2070 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
2071 {
2072 flags >>= 1;
2073 lit = *pLZ_codes++;
2074 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
2075 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
2076
2077 if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
2078 {
2079 flags >>= 1;
2080 lit = *pLZ_codes++;
2081 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
2082 TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
2083 }
2084 }
2085 }
2086
2087 if (pOutput_buf >= d->m_pOutput_buf_end)
2088 return MZ_FALSE;
2089
2090 *(mz_uint64*)pOutput_buf = bit_buffer;
2091 pOutput_buf += (bits_in >> 3);
2092 bit_buffer >>= (bits_in & ~7);
2093 bits_in &= 7;
2094 }
2095
2096#undef TDEFL_PUT_BITS_FAST
2097
2098 d->m_pOutput_buf = pOutput_buf;
2099 d->m_bits_in = 0;
2100 d->m_bit_buffer = 0;
2101
2102 while (bits_in)
2103 {
2104 mz_uint32 n = MZ_MIN(bits_in, 16);
2105 TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
2106 bit_buffer >>= n;
2107 bits_in -= n;
2108 }
2109
2110 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
2111
2112 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
2113}
2114#else
2115static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
2116{
2117 mz_uint flags;
2118 mz_uint8 *pLZ_codes;
2119
2120 flags = 1;
2121 for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
2122 {
2123 if (flags == 1)
2124 flags = *pLZ_codes++ | 0x100;
2125 if (flags & 1)
2126 {
2127 mz_uint sym, num_extra_bits;
2128 mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3;
2129
2130 MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2131 TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
2132 TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
2133
2134 if (match_dist < 512)
2135 {
2136 sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist];
2137 }
2138 else
2139 {
2140 sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
2141 }
2142 MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
2143 TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
2144 TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
2145 }
2146 else
2147 {
2148 mz_uint lit = *pLZ_codes++;
2149 MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
2150 TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
2151 }
2152 }
2153
2154 TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
2155
2156 return (d->m_pOutput_buf < d->m_pOutput_buf_end);
2157}
2158#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS
2159
2160static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
2161{
2162 if (static_block)
2163 tdefl_start_static_block(d);
2164 else
2165 tdefl_start_dynamic_block(d);
2166 return tdefl_compress_lz_codes(d);
2167}
2168
2169static int tdefl_flush_block(tdefl_compressor *d, int flush)
2170{
2171 mz_uint saved_bit_buf, saved_bits_in;
2172 mz_uint8 *pSaved_output_buf;
2173 mz_bool comp_block_succeeded = MZ_FALSE;
2174 int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
2175 mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf;
2176
2177 d->m_pOutput_buf = pOutput_buf_start;
2178 d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
2179
2180 MZ_ASSERT(!d->m_output_flush_remaining);
2181 d->m_output_flush_ofs = 0;
2182 d->m_output_flush_remaining = 0;
2183
2184 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
2185 d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
2186
2187 if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
2188 {
2189 TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8);
2190 }
2191
2192 TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
2193
2194 pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in;
2195
2196 if (!use_raw_block)
2197 comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
2198
2199 // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead.
2200 if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
2201 ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) )
2202 {
2203 mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
2204 TDEFL_PUT_BITS(0, 2);
2205 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
2206 for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
2207 {
2208 TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
2209 }
2210 for (i = 0; i < d->m_total_lz_bytes; ++i)
2211 {
2212 TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
2213 }
2214 }
2215 // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes.
2216 else if (!comp_block_succeeded)
2217 {
2218 d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
2219 tdefl_compress_block(d, MZ_TRUE);
2220 }
2221
2222 if (flush)
2223 {
2224 if (flush == TDEFL_FINISH)
2225 {
2226 if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); }
2227 if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } }
2228 }
2229 else
2230 {
2231 mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); }
2232 }
2233 }
2234
2235 MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
2236
2237 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
2238 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
2239
2240 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++;
2241
2242 if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
2243 {
2244 if (d->m_pPut_buf_func)
2245 {
2246 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
2247 if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
2248 return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
2249 }
2250 else if (pOutput_buf_start == d->m_output_buf)
2251 {
2252 int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
2253 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
2254 d->m_out_buf_ofs += bytes_to_copy;
2255 if ((n -= bytes_to_copy) != 0)
2256 {
2257 d->m_output_flush_ofs = bytes_to_copy;
2258 d->m_output_flush_remaining = n;
2259 }
2260 }
2261 else
2262 {
2263 d->m_out_buf_ofs += n;
2264 }
2265 }
2266
2267 return d->m_output_flush_remaining;
2268}
2269
2270#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2271#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p)
2272static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
2273{
2274 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
2275 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
2276 const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q;
2277 mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
2278 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
2279 for ( ; ; )
2280 {
2281 for ( ; ; )
2282 {
2283 if (--num_probes_left == 0) return;
2284 #define TDEFL_PROBE \
2285 next_probe_pos = d->m_next[probe_pos]; \
2286 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
2287 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
2288 if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break;
2289 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
2290 }
2291 if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32;
2292 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
2293 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
2294 if (!probe_len)
2295 {
2296 *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break;
2297 }
2298 else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len)
2299 {
2300 *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break;
2301 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
2302 }
2303 }
2304}
2305#else
2306static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
2307{
2308 mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
2309 mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
2310 const mz_uint8 *s = d->m_dict + pos, *p, *q;
2311 mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
2312 MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return;
2313 for ( ; ; )
2314 {
2315 for ( ; ; )
2316 {
2317 if (--num_probes_left == 0) return;
2318 #define TDEFL_PROBE \
2319 next_probe_pos = d->m_next[probe_pos]; \
2320 if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \
2321 probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \
2322 if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break;
2323 TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE;
2324 }
2325 if (!dist)
2326 break;
2327 p = s;
2328 q = d->m_dict + probe_pos;
2329 for (probe_len = 0; probe_len < max_match_len; probe_len++)
2330 if (*p++ != *q++) break;
2331 if (probe_len > match_len)
2332 {
2333 *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return;
2334 c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1];
2335 }
2336 }
2337}
2338#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
2339
2340#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
2341static mz_bool tdefl_compress_fast(tdefl_compressor *d)
2342{
2343 // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio.
2344 mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left;
2345 mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
2346 mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
2347
2348 while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
2349 {
2350 const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
2351 mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
2352 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
2353 d->m_src_buf_left -= num_bytes_to_process;
2354 lookahead_size += num_bytes_to_process;
2355
2356 while (num_bytes_to_process)
2357 {
2358 mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
2359 memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
2360 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
2361 memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
2362 d->m_pSrc += n;
2363 dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
2364 num_bytes_to_process -= n;
2365 }
2366
2367 dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
2368 if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break;
2369
2370 while (lookahead_size >= 4)
2371 {
2372 mz_uint cur_match_dist, cur_match_len = 1;
2373 mz_uint8 *pCur_dict = d->m_dict + cur_pos;
2374 mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
2375 mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
2376 mz_uint probe_pos = d->m_hash[hash];
2377 d->m_hash[hash] = (mz_uint16)lookahead_pos;
2378
2379 if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))
2380 {
2381 const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
2382 const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
2383 mz_uint32 probe_len = 32;
2384 do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
2385 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) );
2386 cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
2387 if (!probe_len)
2388 cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
2389
2390 if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)))
2391 {
2392 cur_match_len = 1;
2393 *pLZ_code_buf++ = (mz_uint8)first_trigram;
2394 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
2395 d->m_huff_count[0][(mz_uint8)first_trigram]++;
2396 }
2397 else
2398 {
2399 mz_uint32 s0, s1;
2400 cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
2401
2402 MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
2403
2404 cur_match_dist--;
2405
2406 pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
2407 *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
2408 pLZ_code_buf += 3;
2409 *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
2410
2411 s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
2412 s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
2413 d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
2414
2415 d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
2416 }
2417 }
2418 else
2419 {
2420 *pLZ_code_buf++ = (mz_uint8)first_trigram;
2421 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
2422 d->m_huff_count[0][(mz_uint8)first_trigram]++;
2423 }
2424
2425 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
2426
2427 total_lz_bytes += cur_match_len;
2428 lookahead_pos += cur_match_len;
2429 dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE);
2430 cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
2431 MZ_ASSERT(lookahead_size >= cur_match_len);
2432 lookahead_size -= cur_match_len;
2433
2434 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
2435 {
2436 int n;
2437 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
2438 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
2439 if ((n = tdefl_flush_block(d, 0)) != 0)
2440 return (n < 0) ? MZ_FALSE : MZ_TRUE;
2441 total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
2442 }
2443 }
2444
2445 while (lookahead_size)
2446 {
2447 mz_uint8 lit = d->m_dict[cur_pos];
2448
2449 total_lz_bytes++;
2450 *pLZ_code_buf++ = lit;
2451 *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
2452 if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; }
2453
2454 d->m_huff_count[0][lit]++;
2455
2456 lookahead_pos++;
2457 dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE);
2458 cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
2459 lookahead_size--;
2460
2461 if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
2462 {
2463 int n;
2464 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
2465 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
2466 if ((n = tdefl_flush_block(d, 0)) != 0)
2467 return (n < 0) ? MZ_FALSE : MZ_TRUE;
2468 total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left;
2469 }
2470 }
2471 }
2472
2473 d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size;
2474 d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left;
2475 return MZ_TRUE;
2476}
2477#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
2478
2479static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
2480{
2481 d->m_total_lz_bytes++;
2482 *d->m_pLZ_code_buf++ = lit;
2483 *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
2484 d->m_huff_count[0][lit]++;
2485}
2486
2487static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
2488{
2489 mz_uint32 s0, s1;
2490
2491 MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
2492
2493 d->m_total_lz_bytes += match_len;
2494
2495 d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
2496
2497 match_dist -= 1;
2498 d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
2499 d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3;
2500
2501 *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; }
2502
2503 s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
2504 d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
2505
2506 if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
2507}
2508
2509static mz_bool tdefl_compress_normal(tdefl_compressor *d)
2510{
2511 const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left;
2512 tdefl_flush flush = d->m_flush;
2513
2514 while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
2515 {
2516 mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
2517 // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN.
2518 if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
2519 {
2520 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
2521 mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
2522 mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
2523 const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
2524 src_buf_left -= num_bytes_to_process;
2525 d->m_lookahead_size += num_bytes_to_process;
2526 while (pSrc != pSrc_end)
2527 {
2528 mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
2529 hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
2530 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
2531 dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++;
2532 }
2533 }
2534 else
2535 {
2536 while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
2537 {
2538 mz_uint8 c = *pSrc++;
2539 mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
2540 src_buf_left--;
2541 d->m_dict[dst_pos] = c;
2542 if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
2543 d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
2544 if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
2545 {
2546 mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
2547 mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
2548 d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos);
2549 }
2550 }
2551 }
2552 d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
2553 if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
2554 break;
2555
2556 // Simple lazy/greedy parsing state machine.
2557 len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
2558 if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
2559 {
2560 if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
2561 {
2562 mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
2563 cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; }
2564 if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1;
2565 }
2566 }
2567 else
2568 {
2569 tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
2570 }
2571 if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5)))
2572 {
2573 cur_match_dist = cur_match_len = 0;
2574 }
2575 if (d->m_saved_match_len)
2576 {
2577 if (cur_match_len > d->m_saved_match_len)
2578 {
2579 tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
2580 if (cur_match_len >= 128)
2581 {
2582 tdefl_record_match(d, cur_match_len, cur_match_dist);
2583 d->m_saved_match_len = 0; len_to_move = cur_match_len;
2584 }
2585 else
2586 {
2587 d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
2588 }
2589 }
2590 else
2591 {
2592 tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
2593 len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0;
2594 }
2595 }
2596 else if (!cur_match_dist)
2597 tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
2598 else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
2599 {
2600 tdefl_record_match(d, cur_match_len, cur_match_dist);
2601 len_to_move = cur_match_len;
2602 }
2603 else
2604 {
2605 d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len;
2606 }
2607 // Move the lookahead forward by len_to_move bytes.
2608 d->m_lookahead_pos += len_to_move;
2609 MZ_ASSERT(d->m_lookahead_size >= len_to_move);
2610 d->m_lookahead_size -= len_to_move;
2611 d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE);
2612 // Check if it's time to flush the current LZ codes to the internal output buffer.
2613 if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
2614 ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) )
2615 {
2616 int n;
2617 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
2618 if ((n = tdefl_flush_block(d, 0)) != 0)
2619 return (n < 0) ? MZ_FALSE : MZ_TRUE;
2620 }
2621 }
2622
2623 d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left;
2624 return MZ_TRUE;
2625}
2626
2627static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
2628{
2629 if (d->m_pIn_buf_size)
2630 {
2631 *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
2632 }
2633
2634 if (d->m_pOut_buf_size)
2635 {
2636 size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
2637 memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
2638 d->m_output_flush_ofs += (mz_uint)n;
2639 d->m_output_flush_remaining -= (mz_uint)n;
2640 d->m_out_buf_ofs += n;
2641
2642 *d->m_pOut_buf_size = d->m_out_buf_ofs;
2643 }
2644
2645 return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
2646}
2647
2648tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
2649{
2650 if (!d)
2651 {
2652 if (pIn_buf_size) *pIn_buf_size = 0;
2653 if (pOut_buf_size) *pOut_buf_size = 0;
2654 return TDEFL_STATUS_BAD_PARAM;
2655 }
2656
2657 d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size;
2658 d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size;
2659 d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
2660 d->m_out_buf_ofs = 0;
2661 d->m_flush = flush;
2662
2663 if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
2664 (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) )
2665 {
2666 if (pIn_buf_size) *pIn_buf_size = 0;
2667 if (pOut_buf_size) *pOut_buf_size = 0;
2668 return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
2669 }
2670 d->m_wants_to_finish |= (flush == TDEFL_FINISH);
2671
2672 if ((d->m_output_flush_remaining) || (d->m_finished))
2673 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
2674
2675#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
2676 if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
2677 ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
2678 ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
2679 {
2680 if (!tdefl_compress_fast(d))
2681 return d->m_prev_return_status;
2682 }
2683 else
2684#endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN
2685 {
2686 if (!tdefl_compress_normal(d))
2687 return d->m_prev_return_status;
2688 }
2689
2690 if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
2691 d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
2692
2693 if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
2694 {
2695 if (tdefl_flush_block(d, flush) < 0)
2696 return d->m_prev_return_status;
2697 d->m_finished = (flush == TDEFL_FINISH);
2698 if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; }
2699 }
2700
2701 return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
2702}
2703
2704tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
2705{
2706 MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
2707}
2708
2709tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
2710{
2711 d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user;
2712 d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
2713 d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
2714 if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash);
2715 d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
2716 d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
2717 d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8;
2718 d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY;
2719 d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1;
2720 d->m_pIn_buf = NULL; d->m_pOut_buf = NULL;
2721 d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL;
2722 d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0;
2723 memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
2724 memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
2725 return TDEFL_STATUS_OKAY;
2726}
2727
2728tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
2729{
2730 return d->m_prev_return_status;
2731}
2732
2733mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
2734{
2735 return d->m_adler32;
2736}
2737
2738mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
2739{
2740 tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE;
2741 pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE;
2742 succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
2743 succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
2744 MZ_FREE(pComp); return succeeded;
2745}
2746
2747typedef struct
2748{
2749 size_t m_size, m_capacity;
2750 mz_uint8 *m_pBuf;
2751 mz_bool m_expandable;
2752} tdefl_output_buffer;
2753
2754static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
2755{
2756 tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
2757 size_t new_size = p->m_size + len;
2758 if (new_size > p->m_capacity)
2759 {
2760 size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE;
2761 do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity);
2762 pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE;
2763 p->m_pBuf = pNew_buf; p->m_capacity = new_capacity;
2764 }
2765 memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size;
2766 return MZ_TRUE;
2767}
2768
2769void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
2770{
2771 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
2772 if (!pOut_len) return MZ_FALSE; else *pOut_len = 0;
2773 out_buf.m_expandable = MZ_TRUE;
2774 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL;
2775 *pOut_len = out_buf.m_size; return out_buf.m_pBuf;
2776}
2777
2778size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
2779{
2780 tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf);
2781 if (!pOut_buf) return 0;
2782 out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len;
2783 if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0;
2784 return out_buf.m_size;
2785}
2786
2787#ifndef MINIZ_NO_ZLIB_APIS
2788static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
2789
2790// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files).
2791mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
2792{
2793 mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
2794 if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
2795
2796 if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
2797 else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES;
2798 else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK;
2799 else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
2800 else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES;
2801
2802 return comp_flags;
2803}
2804#endif //MINIZ_NO_ZLIB_APIS
2805
2806#ifdef _MSC_VER
2807#pragma warning (push)
2808#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal)
2809#endif
2810
2811// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
2812// http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
2813// This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck.
2814void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)
2815{
2816 // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined.
2817 static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
2818 tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0;
2819 if (!pComp) return NULL;
2820 MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; }
2821 // write dummy header
2822 for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf);
2823 // compress image data
2824 tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
2825 for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); }
2826 if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
2827 // write real header
2828 *pLen_out = out_buf.m_size-41;
2829 {
2830 static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06};
2831 mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
2832 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0,
2833 (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54};
2834 c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24);
2835 memcpy(out_buf.m_pBuf, pnghdr, 41);
2836 }
2837 // write footer (IDAT CRC-32, followed by IEND chunk)
2838 if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; }
2839 c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24);
2840 // compute final size of file, grab compressed data buffer and return
2841 *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf;
2842}
2843void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)
2844{
2845 // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out)
2846 return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);
2847}
2848
2849#ifdef _MSC_VER
2850#pragma warning (pop)
2851#endif
2852
2853// ------------------- .ZIP archive reading
2854
2855#ifndef MINIZ_NO_ARCHIVE_APIS
2856
2857#ifdef MINIZ_NO_STDIO
2858 #define MZ_FILE void *
2859#else
2860 #include <stdio.h>
2861 #include <sys/stat.h>
2862
2863 #if defined(_MSC_VER) || defined(__MINGW64__)
2864 static FILE *mz_fopen(const char *pFilename, const char *pMode)
2865 {
2866 FILE* pFile = NULL;
2867 fopen_s(&pFile, pFilename, pMode);
2868 return pFile;
2869 }
2870 static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
2871 {
2872 FILE* pFile = NULL;
2873 if (freopen_s(&pFile, pPath, pMode, pStream))
2874 return NULL;
2875 return pFile;
2876 }
2877 #ifndef MINIZ_NO_TIME
2878 #include <sys/utime.h>
2879 #endif
2880 #define MZ_FILE FILE
2881 #define MZ_FOPEN mz_fopen
2882 #define MZ_FCLOSE fclose
2883 #define MZ_FREAD fread
2884 #define MZ_FWRITE fwrite
2885 #define MZ_FTELL64 _ftelli64
2886 #define MZ_FSEEK64 _fseeki64
2887 #define MZ_FILE_STAT_STRUCT _stat
2888 #define MZ_FILE_STAT _stat
2889 #define MZ_FFLUSH fflush
2890 #define MZ_FREOPEN mz_freopen
2891 #define MZ_DELETE_FILE remove
2892 #elif defined(__MINGW32__)
2893 #ifndef MINIZ_NO_TIME
2894 #include <sys/utime.h>
2895 #endif
2896 #define MZ_FILE FILE
2897 #define MZ_FOPEN(f, m) fopen(f, m)
2898 #define MZ_FCLOSE fclose
2899 #define MZ_FREAD fread
2900 #define MZ_FWRITE fwrite
2901 #define MZ_FTELL64 ftello64
2902 #define MZ_FSEEK64 fseeko64
2903 #define MZ_FILE_STAT_STRUCT _stat
2904 #define MZ_FILE_STAT _stat
2905 #define MZ_FFLUSH fflush
2906 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
2907 #define MZ_DELETE_FILE remove
2908 #elif defined(__TINYC__)
2909 #ifndef MINIZ_NO_TIME
2910 #include <sys/utime.h>
2911 #endif
2912 #define MZ_FILE FILE
2913 #define MZ_FOPEN(f, m) fopen(f, m)
2914 #define MZ_FCLOSE fclose
2915 #define MZ_FREAD fread
2916 #define MZ_FWRITE fwrite
2917 #define MZ_FTELL64 ftell
2918 #define MZ_FSEEK64 fseek
2919 #define MZ_FILE_STAT_STRUCT stat
2920 #define MZ_FILE_STAT stat
2921 #define MZ_FFLUSH fflush
2922 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
2923 #define MZ_DELETE_FILE remove
2924 #elif defined(__GNUC__) && _LARGEFILE64_SOURCE
2925 #ifndef MINIZ_NO_TIME
2926 #include <utime.h>
2927 #endif
2928 #define MZ_FILE FILE
2929 #define MZ_FOPEN(f, m) fopen64(f, m)
2930 #define MZ_FCLOSE fclose
2931 #define MZ_FREAD fread
2932 #define MZ_FWRITE fwrite
2933 #define MZ_FTELL64 ftello64
2934 #define MZ_FSEEK64 fseeko64
2935 #define MZ_FILE_STAT_STRUCT stat64
2936 #define MZ_FILE_STAT stat64
2937 #define MZ_FFLUSH fflush
2938 #define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
2939 #define MZ_DELETE_FILE remove
2940 #else
2941 #ifndef MINIZ_NO_TIME
2942 #include <utime.h>
2943 #endif
2944 #define MZ_FILE FILE
2945 #define MZ_FOPEN(f, m) fopen(f, m)
2946 #define MZ_FCLOSE fclose
2947 #define MZ_FREAD fread
2948 #define MZ_FWRITE fwrite
2949 #define MZ_FTELL64 ftello
2950 #define MZ_FSEEK64 fseeko
2951 #define MZ_FILE_STAT_STRUCT stat
2952 #define MZ_FILE_STAT stat
2953 #define MZ_FFLUSH fflush
2954 #define MZ_FREOPEN(f, m, s) freopen(f, m, s)
2955 #define MZ_DELETE_FILE remove
2956 #endif // #ifdef _MSC_VER
2957#endif // #ifdef MINIZ_NO_STDIO
2958
2959#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
2960
2961// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff.
2962enum
2963{
2964 // ZIP archive identifiers and record sizes
2965 MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
2966 MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
2967 // Central directory header record offsets
2968 MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
2969 MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16,
2970 MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
2971 MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
2972 // Local directory header offsets
2973 MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10,
2974 MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
2975 MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
2976 // End of central directory offsets
2977 MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
2978 MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
2979};
2980
2981typedef struct
2982{
2983 void *m_p;
2984 size_t m_size, m_capacity;
2985 mz_uint m_element_size;
2986} mz_zip_array;
2987
2988struct mz_zip_internal_state_tag
2989{
2990 mz_zip_array m_central_dir;
2991 mz_zip_array m_central_dir_offsets;
2992 mz_zip_array m_sorted_central_dir_offsets;
2993 MZ_FILE *m_pFile;
2994 void *m_pMem;
2995 size_t m_mem_size;
2996 size_t m_mem_capacity;
2997};
2998
2999#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
3000#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
3001
3002static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
3003{
3004 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
3005 memset(pArray, 0, sizeof(mz_zip_array));
3006}
3007
3008static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
3009{
3010 void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE;
3011 if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; }
3012 if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE;
3013 pArray->m_p = pNew_p; pArray->m_capacity = new_capacity;
3014 return MZ_TRUE;
3015}
3016
3017static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
3018{
3019 if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; }
3020 return MZ_TRUE;
3021}
3022
3023static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
3024{
3025 if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; }
3026 pArray->m_size = new_size;
3027 return MZ_TRUE;
3028}
3029
3030static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
3031{
3032 return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
3033}
3034
3035static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
3036{
3037 size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE;
3038 memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
3039 return MZ_TRUE;
3040}
3041
3042#ifndef MINIZ_NO_TIME
3043static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date)
3044{
3045 struct tm tm;
3046 memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1;
3047 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31;
3048 tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62;
3049 return mktime(&tm);
3050}
3051
3052static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
3053{
3054#ifdef _MSC_VER
3055 struct tm tm_struct;
3056 struct tm *tm = &tm_struct;
3057 errno_t err = localtime_s(tm, &time);
3058 if (err)
3059 {
3060 *pDOS_date = 0; *pDOS_time = 0;
3061 return;
3062 }
3063#else
3064 struct tm *tm = localtime(&time);
3065#endif
3066 *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
3067 *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
3068}
3069#endif
3070
3071#ifndef MINIZ_NO_STDIO
3072static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
3073{
3074#ifdef MINIZ_NO_TIME
3075 (void)pFilename; *pDOS_date = *pDOS_time = 0;
3076#else
3077 struct MZ_FILE_STAT_STRUCT file_stat;
3078 // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh.
3079 if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
3080 return MZ_FALSE;
3081 mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date);
3082#endif // #ifdef MINIZ_NO_TIME
3083 return MZ_TRUE;
3084}
3085
3086#ifndef MINIZ_NO_TIME
3087static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time)
3088{
3089 struct utimbuf t; t.actime = access_time; t.modtime = modified_time;
3090 return !utime(pFilename, &t);
3091}
3092#endif // #ifndef MINIZ_NO_TIME
3093#endif // #ifndef MINIZ_NO_STDIO
3094
3095static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags)
3096{
3097 (void)flags;
3098 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
3099 return MZ_FALSE;
3100
3101 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
3102 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
3103 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
3104
3105 pZip->m_zip_mode = MZ_ZIP_MODE_READING;
3106 pZip->m_archive_size = 0;
3107 pZip->m_central_directory_file_ofs = 0;
3108 pZip->m_total_files = 0;
3109
3110 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
3111 return MZ_FALSE;
3112 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
3113 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
3114 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
3115 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
3116 return MZ_TRUE;
3117}
3118
3119static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
3120{
3121 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
3122 const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
3123 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3124 mz_uint8 l = 0, r = 0;
3125 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
3126 pE = pL + MZ_MIN(l_len, r_len);
3127 while (pL < pE)
3128 {
3129 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
3130 break;
3131 pL++; pR++;
3132 }
3133 return (pL == pE) ? (l_len < r_len) : (l < r);
3134}
3135
3136#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END
3137
3138// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.)
3139static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
3140{
3141 mz_zip_internal_state *pState = pZip->m_pState;
3142 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
3143 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
3144 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
3145 const int size = pZip->m_total_files;
3146 int start = (size - 2) >> 1, end;
3147 while (start >= 0)
3148 {
3149 int child, root = start;
3150 for ( ; ; )
3151 {
3152 if ((child = (root << 1) + 1) >= size)
3153 break;
3154 child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])));
3155 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
3156 break;
3157 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
3158 }
3159 start--;
3160 }
3161
3162 end = size - 1;
3163 while (end > 0)
3164 {
3165 int child, root = 0;
3166 MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
3167 for ( ; ; )
3168 {
3169 if ((child = (root << 1) + 1) >= end)
3170 break;
3171 child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]));
3172 if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
3173 break;
3174 MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
3175 }
3176 end--;
3177 }
3178}
3179
3180static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags)
3181{
3182 mz_uint cdir_size, num_this_disk, cdir_disk_index;
3183 mz_uint64 cdir_ofs;
3184 mz_int64 cur_file_ofs;
3185 const mz_uint8 *p;
3186 mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
3187 mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
3188 // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there.
3189 if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
3190 return MZ_FALSE;
3191 // Find the end of central directory record by scanning the file from the end towards the beginning.
3192 cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
3193 for ( ; ; )
3194 {
3195 int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
3196 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
3197 return MZ_FALSE;
3198 for (i = n - 4; i >= 0; --i)
3199 if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
3200 break;
3201 if (i >= 0)
3202 {
3203 cur_file_ofs += i;
3204 break;
3205 }
3206 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
3207 return MZ_FALSE;
3208 cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
3209 }
3210 // Read and verify the end of central directory record.
3211 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
3212 return MZ_FALSE;
3213 if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
3214 ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
3215 return MZ_FALSE;
3216
3217 num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
3218 cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
3219 if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
3220 return MZ_FALSE;
3221
3222 if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
3223 return MZ_FALSE;
3224
3225 cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
3226 if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
3227 return MZ_FALSE;
3228
3229 pZip->m_central_directory_file_ofs = cdir_ofs;
3230
3231 if (pZip->m_total_files)
3232 {
3233 mz_uint i, n;
3234
3235 // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices.
3236 if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
3237 (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
3238 return MZ_FALSE;
3239
3240 if (sort_central_dir)
3241 {
3242 if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))
3243 return MZ_FALSE;
3244 }
3245
3246 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
3247 return MZ_FALSE;
3248
3249 // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported).
3250 p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
3251 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
3252 {
3253 mz_uint total_header_size, comp_size, decomp_size, disk_index;
3254 if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
3255 return MZ_FALSE;
3256 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
3257 if (sort_central_dir)
3258 MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
3259 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3260 decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
3261 if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF))
3262 return MZ_FALSE;
3263 disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
3264 if ((disk_index != num_this_disk) && (disk_index != 1))
3265 return MZ_FALSE;
3266 if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
3267 return MZ_FALSE;
3268 if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)
3269 return MZ_FALSE;
3270 n -= total_header_size; p += total_header_size;
3271 }
3272 }
3273
3274 if (sort_central_dir)
3275 mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
3276
3277 return MZ_TRUE;
3278}
3279
3280mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags)
3281{
3282 if ((!pZip) || (!pZip->m_pRead))
3283 return MZ_FALSE;
3284 if (!mz_zip_reader_init_internal(pZip, flags))
3285 return MZ_FALSE;
3286 pZip->m_archive_size = size;
3287 if (!mz_zip_reader_read_central_dir(pZip, flags))
3288 {
3289 mz_zip_reader_end(pZip);
3290 return MZ_FALSE;
3291 }
3292 return MZ_TRUE;
3293}
3294
3295static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
3296{
3297 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3298 size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
3299 memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
3300 return s;
3301}
3302
3303mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags)
3304{
3305 if (!mz_zip_reader_init_internal(pZip, flags))
3306 return MZ_FALSE;
3307 pZip->m_archive_size = size;
3308 pZip->m_pRead = mz_zip_mem_read_func;
3309 pZip->m_pIO_opaque = pZip;
3310#ifdef __cplusplus
3311 pZip->m_pState->m_pMem = const_cast<void *>(pMem);
3312#else
3313 pZip->m_pState->m_pMem = (void *)pMem;
3314#endif
3315 pZip->m_pState->m_mem_size = size;
3316 if (!mz_zip_reader_read_central_dir(pZip, flags))
3317 {
3318 mz_zip_reader_end(pZip);
3319 return MZ_FALSE;
3320 }
3321 return MZ_TRUE;
3322}
3323
3324#ifndef MINIZ_NO_STDIO
3325static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
3326{
3327 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
3328 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
3329 if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
3330 return 0;
3331 return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
3332}
3333
3334mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
3335{
3336 mz_uint64 file_size;
3337 MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb");
3338 if (!pFile)
3339 return MZ_FALSE;
3340 if (MZ_FSEEK64(pFile, 0, SEEK_END))
3341 {
3342 MZ_FCLOSE(pFile);
3343 return MZ_FALSE;
3344 }
3345 file_size = MZ_FTELL64(pFile);
3346 if (!mz_zip_reader_init_internal(pZip, flags))
3347 {
3348 MZ_FCLOSE(pFile);
3349 return MZ_FALSE;
3350 }
3351 pZip->m_pRead = mz_zip_file_read_func;
3352 pZip->m_pIO_opaque = pZip;
3353 pZip->m_pState->m_pFile = pFile;
3354 pZip->m_archive_size = file_size;
3355 if (!mz_zip_reader_read_central_dir(pZip, flags))
3356 {
3357 mz_zip_reader_end(pZip);
3358 return MZ_FALSE;
3359 }
3360 return MZ_TRUE;
3361}
3362#endif // #ifndef MINIZ_NO_STDIO
3363
3364mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
3365{
3366 return pZip ? pZip->m_total_files : 0;
3367}
3368
3369static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
3370{
3371 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3372 return NULL;
3373 return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
3374}
3375
3376mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
3377{
3378 mz_uint m_bit_flag;
3379 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
3380 if (!p)
3381 return MZ_FALSE;
3382 m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
3383 return (m_bit_flag & 1);
3384}
3385
3386mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
3387{
3388 mz_uint filename_len, external_attr;
3389 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
3390 if (!p)
3391 return MZ_FALSE;
3392
3393 // First see if the filename ends with a '/' character.
3394 filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3395 if (filename_len)
3396 {
3397 if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
3398 return MZ_TRUE;
3399 }
3400
3401 // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct.
3402 // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field.
3403 // FIXME: Remove this check? Is it necessary - we already check the filename.
3404 external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
3405 if ((external_attr & 0x10) != 0)
3406 return MZ_TRUE;
3407
3408 return MZ_FALSE;
3409}
3410
3411mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
3412{
3413 mz_uint n;
3414 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
3415 if ((!p) || (!pStat))
3416 return MZ_FALSE;
3417
3418 // Unpack the central directory record.
3419 pStat->m_file_index = file_index;
3420 pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
3421 pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
3422 pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
3423 pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
3424 pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
3425#ifndef MINIZ_NO_TIME
3426 pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
3427#endif
3428 pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
3429 pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3430 pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
3431 pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
3432 pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
3433 pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
3434
3435 // Copy as much of the filename and comment as possible.
3436 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
3437 memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0';
3438
3439 n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
3440 pStat->m_comment_size = n;
3441 memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0';
3442
3443 return MZ_TRUE;
3444}
3445
3446mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
3447{
3448 mz_uint n;
3449 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
3450 if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; }
3451 n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3452 if (filename_buf_size)
3453 {
3454 n = MZ_MIN(n, filename_buf_size - 1);
3455 memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
3456 pFilename[n] = '\0';
3457 }
3458 return n + 1;
3459}
3460
3461static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
3462{
3463 mz_uint i;
3464 if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
3465 return 0 == memcmp(pA, pB, len);
3466 for (i = 0; i < len; ++i)
3467 if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
3468 return MZ_FALSE;
3469 return MZ_TRUE;
3470}
3471
3472static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len)
3473{
3474 const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
3475 mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3476 mz_uint8 l = 0, r = 0;
3477 pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
3478 pE = pL + MZ_MIN(l_len, r_len);
3479 while (pL < pE)
3480 {
3481 if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
3482 break;
3483 pL++; pR++;
3484 }
3485 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
3486}
3487
3488static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename)
3489{
3490 mz_zip_internal_state *pState = pZip->m_pState;
3491 const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
3492 const mz_zip_array *pCentral_dir = &pState->m_central_dir;
3493 mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
3494 const int size = pZip->m_total_files;
3495 const mz_uint filename_len = (mz_uint)strlen(pFilename);
3496 int l = 0, h = size - 1;
3497 while (l <= h)
3498 {
3499 int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
3500 if (!comp)
3501 return file_index;
3502 else if (comp < 0)
3503 l = m + 1;
3504 else
3505 h = m - 1;
3506 }
3507 return -1;
3508}
3509
3510int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
3511{
3512 mz_uint file_index; size_t name_len, comment_len;
3513 if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3514 return -1;
3515 if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
3516 return mz_zip_reader_locate_file_binary_search(pZip, pName);
3517 name_len = strlen(pName); if (name_len > 0xFFFF) return -1;
3518 comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1;
3519 for (file_index = 0; file_index < pZip->m_total_files; file_index++)
3520 {
3521 const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
3522 mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
3523 const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
3524 if (filename_len < name_len)
3525 continue;
3526 if (comment_len)
3527 {
3528 mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
3529 const char *pFile_comment = pFilename + filename_len + file_extra_len;
3530 if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags)))
3531 continue;
3532 }
3533 if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
3534 {
3535 int ofs = filename_len - 1;
3536 do
3537 {
3538 if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
3539 break;
3540 } while (--ofs >= 0);
3541 ofs++;
3542 pFilename += ofs; filename_len -= ofs;
3543 }
3544 if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
3545 return file_index;
3546 }
3547 return -1;
3548}
3549
3550mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
3551{
3552 int status = TINFL_STATUS_DONE;
3553 mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
3554 mz_zip_archive_file_stat file_stat;
3555 void *pRead_buf;
3556 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
3557 tinfl_decompressor inflator;
3558
3559 if ((buf_size) && (!pBuf))
3560 return MZ_FALSE;
3561
3562 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
3563 return MZ_FALSE;
3564
3565 // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes)
3566 if (!file_stat.m_comp_size)
3567 return MZ_TRUE;
3568
3569 // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers).
3570 // I'm torn how to handle this case - should it fail instead?
3571 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
3572 return MZ_TRUE;
3573
3574 // Encryption and patch files are not supported.
3575 if (file_stat.m_bit_flag & (1 | 32))
3576 return MZ_FALSE;
3577
3578 // This function only supports stored and deflate.
3579 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
3580 return MZ_FALSE;
3581
3582 // Ensure supplied output buffer is large enough.
3583 needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
3584 if (buf_size < needed_size)
3585 return MZ_FALSE;
3586
3587 // Read and parse the local directory entry.
3588 cur_file_ofs = file_stat.m_local_header_ofs;
3589 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3590 return MZ_FALSE;
3591 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
3592 return MZ_FALSE;
3593
3594 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
3595 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
3596 return MZ_FALSE;
3597
3598 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
3599 {
3600 // The file is stored or the caller has requested the compressed data.
3601 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
3602 return MZ_FALSE;
3603 return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
3604 }
3605
3606 // Decompress the file either directly from memory or from a file input buffer.
3607 tinfl_init(&inflator);
3608
3609 if (pZip->m_pState->m_pMem)
3610 {
3611 // Read directly from the archive in memory.
3612 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
3613 read_buf_size = read_buf_avail = file_stat.m_comp_size;
3614 comp_remaining = 0;
3615 }
3616 else if (pUser_read_buf)
3617 {
3618 // Use a user provided read buffer.
3619 if (!user_read_buf_size)
3620 return MZ_FALSE;
3621 pRead_buf = (mz_uint8 *)pUser_read_buf;
3622 read_buf_size = user_read_buf_size;
3623 read_buf_avail = 0;
3624 comp_remaining = file_stat.m_comp_size;
3625 }
3626 else
3627 {
3628 // Temporarily allocate a read buffer.
3629 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
3630#ifdef _MSC_VER
3631 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
3632#else
3633 if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
3634#endif
3635 return MZ_FALSE;
3636 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
3637 return MZ_FALSE;
3638 read_buf_avail = 0;
3639 comp_remaining = file_stat.m_comp_size;
3640 }
3641
3642 do
3643 {
3644 size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
3645 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
3646 {
3647 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
3648 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
3649 {
3650 status = TINFL_STATUS_FAILED;
3651 break;
3652 }
3653 cur_file_ofs += read_buf_avail;
3654 comp_remaining -= read_buf_avail;
3655 read_buf_ofs = 0;
3656 }
3657 in_buf_size = (size_t)read_buf_avail;
3658 status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
3659 read_buf_avail -= in_buf_size;
3660 read_buf_ofs += in_buf_size;
3661 out_buf_ofs += out_buf_size;
3662 } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
3663
3664 if (status == TINFL_STATUS_DONE)
3665 {
3666 // Make sure the entire file was decompressed, and check its CRC.
3667 if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
3668 status = TINFL_STATUS_FAILED;
3669 }
3670
3671 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
3672 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3673
3674 return status == TINFL_STATUS_DONE;
3675}
3676
3677mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
3678{
3679 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
3680 if (file_index < 0)
3681 return MZ_FALSE;
3682 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
3683}
3684
3685mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
3686{
3687 return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
3688}
3689
3690mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)
3691{
3692 return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
3693}
3694
3695void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
3696{
3697 mz_uint64 comp_size, uncomp_size, alloc_size;
3698 const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index);
3699 void *pBuf;
3700
3701 if (pSize)
3702 *pSize = 0;
3703 if (!p)
3704 return NULL;
3705
3706 comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
3707 uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
3708
3709 alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
3710#ifdef _MSC_VER
3711 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
3712#else
3713 if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
3714#endif
3715 return NULL;
3716 if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
3717 return NULL;
3718
3719 if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
3720 {
3721 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
3722 return NULL;
3723 }
3724
3725 if (pSize) *pSize = (size_t)alloc_size;
3726 return pBuf;
3727}
3728
3729void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
3730{
3731 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
3732 if (file_index < 0)
3733 {
3734 if (pSize) *pSize = 0;
3735 return MZ_FALSE;
3736 }
3737 return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
3738}
3739
3740mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
3741{
3742 int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT;
3743 mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
3744 mz_zip_archive_file_stat file_stat;
3745 void *pRead_buf = NULL; void *pWrite_buf = NULL;
3746 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
3747
3748 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
3749 return MZ_FALSE;
3750
3751 // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes)
3752 if (!file_stat.m_comp_size)
3753 return MZ_TRUE;
3754
3755 // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers).
3756 // I'm torn how to handle this case - should it fail instead?
3757 if (mz_zip_reader_is_file_a_directory(pZip, file_index))
3758 return MZ_TRUE;
3759
3760 // Encryption and patch files are not supported.
3761 if (file_stat.m_bit_flag & (1 | 32))
3762 return MZ_FALSE;
3763
3764 // This function only supports stored and deflate.
3765 if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
3766 return MZ_FALSE;
3767
3768 // Read and parse the local directory entry.
3769 cur_file_ofs = file_stat.m_local_header_ofs;
3770 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
3771 return MZ_FALSE;
3772 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
3773 return MZ_FALSE;
3774
3775 cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
3776 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
3777 return MZ_FALSE;
3778
3779 // Decompress the file either directly from memory or from a file input buffer.
3780 if (pZip->m_pState->m_pMem)
3781 {
3782 pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
3783 read_buf_size = read_buf_avail = file_stat.m_comp_size;
3784 comp_remaining = 0;
3785 }
3786 else
3787 {
3788 read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE);
3789 if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
3790 return MZ_FALSE;
3791 read_buf_avail = 0;
3792 comp_remaining = file_stat.m_comp_size;
3793 }
3794
3795 if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
3796 {
3797 // The file is stored or the caller has requested the compressed data.
3798 if (pZip->m_pState->m_pMem)
3799 {
3800#ifdef _MSC_VER
3801 if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
3802#else
3803 if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF))
3804#endif
3805 return MZ_FALSE;
3806 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
3807 status = TINFL_STATUS_FAILED;
3808 else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3809 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
3810 cur_file_ofs += file_stat.m_comp_size;
3811 out_buf_ofs += file_stat.m_comp_size;
3812 comp_remaining = 0;
3813 }
3814 else
3815 {
3816 while (comp_remaining)
3817 {
3818 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
3819 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
3820 {
3821 status = TINFL_STATUS_FAILED;
3822 break;
3823 }
3824
3825 if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
3826 file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
3827
3828 if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
3829 {
3830 status = TINFL_STATUS_FAILED;
3831 break;
3832 }
3833 cur_file_ofs += read_buf_avail;
3834 out_buf_ofs += read_buf_avail;
3835 comp_remaining -= read_buf_avail;
3836 }
3837 }
3838 }
3839 else
3840 {
3841 tinfl_decompressor inflator;
3842 tinfl_init(&inflator);
3843
3844 if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
3845 status = TINFL_STATUS_FAILED;
3846 else
3847 {
3848 do
3849 {
3850 mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
3851 size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
3852 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
3853 {
3854 read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
3855 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
3856 {
3857 status = TINFL_STATUS_FAILED;
3858 break;
3859 }
3860 cur_file_ofs += read_buf_avail;
3861 comp_remaining -= read_buf_avail;
3862 read_buf_ofs = 0;
3863 }
3864
3865 in_buf_size = (size_t)read_buf_avail;
3866 status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
3867 read_buf_avail -= in_buf_size;
3868 read_buf_ofs += in_buf_size;
3869
3870 if (out_buf_size)
3871 {
3872 if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
3873 {
3874 status = TINFL_STATUS_FAILED;
3875 break;
3876 }
3877 file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
3878 if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
3879 {
3880 status = TINFL_STATUS_FAILED;
3881 break;
3882 }
3883 }
3884 } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
3885 }
3886 }
3887
3888 if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
3889 {
3890 // Make sure the entire file was decompressed, and check its CRC.
3891 if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32))
3892 status = TINFL_STATUS_FAILED;
3893 }
3894
3895 if (!pZip->m_pState->m_pMem)
3896 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
3897 if (pWrite_buf)
3898 pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
3899
3900 return status == TINFL_STATUS_DONE;
3901}
3902
3903mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
3904{
3905 int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags);
3906 if (file_index < 0)
3907 return MZ_FALSE;
3908 return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
3909}
3910
3911#ifndef MINIZ_NO_STDIO
3912static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
3913{
3914 (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque);
3915}
3916
3917mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
3918{
3919 mz_bool status;
3920 mz_zip_archive_file_stat file_stat;
3921 MZ_FILE *pFile;
3922 if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
3923 return MZ_FALSE;
3924 pFile = MZ_FOPEN(pDst_filename, "wb");
3925 if (!pFile)
3926 return MZ_FALSE;
3927 status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
3928 if (MZ_FCLOSE(pFile) == EOF)
3929 return MZ_FALSE;
3930#ifndef MINIZ_NO_TIME
3931 if (status)
3932 mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
3933#endif
3934 return status;
3935}
3936#endif // #ifndef MINIZ_NO_STDIO
3937
3938mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
3939{
3940 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
3941 return MZ_FALSE;
3942
3943 if (pZip->m_pState)
3944 {
3945 mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL;
3946 mz_zip_array_clear(pZip, &pState->m_central_dir);
3947 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
3948 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
3949
3950#ifndef MINIZ_NO_STDIO
3951 if (pState->m_pFile)
3952 {
3953 MZ_FCLOSE(pState->m_pFile);
3954 pState->m_pFile = NULL;
3955 }
3956#endif // #ifndef MINIZ_NO_STDIO
3957
3958 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
3959 }
3960 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
3961
3962 return MZ_TRUE;
3963}
3964
3965#ifndef MINIZ_NO_STDIO
3966mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
3967{
3968 int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags);
3969 if (file_index < 0)
3970 return MZ_FALSE;
3971 return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
3972}
3973#endif
3974
3975// ------------------- .ZIP archive writing
3976
3977#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
3978
3979static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); }
3980static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); }
3981#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
3982#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
3983
3984mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
3985{
3986 if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
3987 return MZ_FALSE;
3988
3989 if (pZip->m_file_offset_alignment)
3990 {
3991 // Ensure user specified file offset alignment is a power of 2.
3992 if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
3993 return MZ_FALSE;
3994 }
3995
3996 if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func;
3997 if (!pZip->m_pFree) pZip->m_pFree = def_free_func;
3998 if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func;
3999
4000 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
4001 pZip->m_archive_size = existing_size;
4002 pZip->m_central_directory_file_ofs = 0;
4003 pZip->m_total_files = 0;
4004
4005 if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
4006 return MZ_FALSE;
4007 memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
4008 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
4009 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
4010 MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
4011 return MZ_TRUE;
4012}
4013
4014static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
4015{
4016 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
4017 mz_zip_internal_state *pState = pZip->m_pState;
4018 mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
4019#ifdef _MSC_VER
4020 if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
4021#else
4022 if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF)))
4023#endif
4024 return 0;
4025 if (new_size > pState->m_mem_capacity)
4026 {
4027 void *pNew_block;
4028 size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2;
4029 if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
4030 return 0;
4031 pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity;
4032 }
4033 memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
4034 pState->m_mem_size = (size_t)new_size;
4035 return n;
4036}
4037
4038mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
4039{
4040 pZip->m_pWrite = mz_zip_heap_write_func;
4041 pZip->m_pIO_opaque = pZip;
4042 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
4043 return MZ_FALSE;
4044 if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
4045 {
4046 if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
4047 {
4048 mz_zip_writer_end(pZip);
4049 return MZ_FALSE;
4050 }
4051 pZip->m_pState->m_mem_capacity = initial_allocation_size;
4052 }
4053 return MZ_TRUE;
4054}
4055
4056#ifndef MINIZ_NO_STDIO
4057static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
4058{
4059 mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
4060 mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
4061 if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
4062 return 0;
4063 return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
4064}
4065
4066mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
4067{
4068 MZ_FILE *pFile;
4069 pZip->m_pWrite = mz_zip_file_write_func;
4070 pZip->m_pIO_opaque = pZip;
4071 if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning))
4072 return MZ_FALSE;
4073 if (NULL == (pFile = MZ_FOPEN(pFilename, "wb")))
4074 {
4075 mz_zip_writer_end(pZip);
4076 return MZ_FALSE;
4077 }
4078 pZip->m_pState->m_pFile = pFile;
4079 if (size_to_reserve_at_beginning)
4080 {
4081 mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf);
4082 do
4083 {
4084 size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
4085 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
4086 {
4087 mz_zip_writer_end(pZip);
4088 return MZ_FALSE;
4089 }
4090 cur_ofs += n; size_to_reserve_at_beginning -= n;
4091 } while (size_to_reserve_at_beginning);
4092 }
4093 return MZ_TRUE;
4094}
4095#endif // #ifndef MINIZ_NO_STDIO
4096
4097mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
4098{
4099 mz_zip_internal_state *pState;
4100 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
4101 return MZ_FALSE;
4102 // No sense in trying to write to an archive that's already at the support max size
4103 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
4104 return MZ_FALSE;
4105
4106 pState = pZip->m_pState;
4107
4108 if (pState->m_pFile)
4109 {
4110#ifdef MINIZ_NO_STDIO
4111 pFilename; return MZ_FALSE;
4112#else
4113 // Archive is being read from stdio - try to reopen as writable.
4114 if (pZip->m_pIO_opaque != pZip)
4115 return MZ_FALSE;
4116 if (!pFilename)
4117 return MZ_FALSE;
4118 pZip->m_pWrite = mz_zip_file_write_func;
4119 if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
4120 {
4121 // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it.
4122 mz_zip_reader_end(pZip);
4123 return MZ_FALSE;
4124 }
4125#endif // #ifdef MINIZ_NO_STDIO
4126 }
4127 else if (pState->m_pMem)
4128 {
4129 // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback.
4130 if (pZip->m_pIO_opaque != pZip)
4131 return MZ_FALSE;
4132 pState->m_mem_capacity = pState->m_mem_size;
4133 pZip->m_pWrite = mz_zip_heap_write_func;
4134 }
4135 // Archive is being read via a user provided read function - make sure the user has specified a write function too.
4136 else if (!pZip->m_pWrite)
4137 return MZ_FALSE;
4138
4139 // Start writing new files at the archive's current central directory location.
4140 pZip->m_archive_size = pZip->m_central_directory_file_ofs;
4141 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
4142 pZip->m_central_directory_file_ofs = 0;
4143
4144 return MZ_TRUE;
4145}
4146
4147mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)
4148{
4149 return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
4150}
4151
4152typedef struct
4153{
4154 mz_zip_archive *m_pZip;
4155 mz_uint64 m_cur_archive_file_ofs;
4156 mz_uint64 m_comp_size;
4157} mz_zip_writer_add_state;
4158
4159static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser)
4160{
4161 mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
4162 if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
4163 return MZ_FALSE;
4164 pState->m_cur_archive_file_ofs += len;
4165 pState->m_comp_size += len;
4166 return MZ_TRUE;
4167}
4168
4169static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
4170{
4171 (void)pZip;
4172 memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
4173 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
4174 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
4175 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
4176 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
4177 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
4178 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
4179 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
4180 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size);
4181 MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
4182 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
4183 MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
4184 return MZ_TRUE;
4185}
4186
4187static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
4188{
4189 (void)pZip;
4190 memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
4191 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
4192 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
4193 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
4194 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
4195 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
4196 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
4197 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
4198 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size);
4199 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size);
4200 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
4201 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
4202 MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
4203 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
4204 MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs);
4205 return MZ_TRUE;
4206}
4207
4208static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
4209{
4210 mz_zip_internal_state *pState = pZip->m_pState;
4211 mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
4212 size_t orig_central_dir_size = pState->m_central_dir.m_size;
4213 mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
4214
4215 // No zip64 support yet
4216 if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF))
4217 return MZ_FALSE;
4218
4219 if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))
4220 return MZ_FALSE;
4221
4222 if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
4223 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
4224 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
4225 (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
4226 (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &central_dir_ofs, 1)))
4227 {
4228 // Try to push the central directory array back into its original state.
4229 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4230 return MZ_FALSE;
4231 }
4232
4233 return MZ_TRUE;
4234}
4235
4236static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
4237{
4238 // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes.
4239 if (*pArchive_name == '/')
4240 return MZ_FALSE;
4241 while (*pArchive_name)
4242 {
4243 if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
4244 return MZ_FALSE;
4245 pArchive_name++;
4246 }
4247 return MZ_TRUE;
4248}
4249
4250static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
4251{
4252 mz_uint32 n;
4253 if (!pZip->m_file_offset_alignment)
4254 return 0;
4255 n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
4256 return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1);
4257}
4258
4259static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
4260{
4261 char buf[4096];
4262 memset(buf, 0, MZ_MIN(sizeof(buf), n));
4263 while (n)
4264 {
4265 mz_uint32 s = MZ_MIN(sizeof(buf), n);
4266 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
4267 return MZ_FALSE;
4268 cur_file_ofs += s; n -= s;
4269 }
4270 return MZ_TRUE;
4271}
4272
4273mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
4274{
4275 mz_uint16 method = 0, dos_time = 0, dos_date = 0;
4276 mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
4277 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
4278 size_t archive_name_size;
4279 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
4280 tdefl_compressor *pComp = NULL;
4281 mz_bool store_data_uncompressed;
4282 mz_zip_internal_state *pState;
4283
4284 if ((int)level_and_flags < 0)
4285 level_and_flags = MZ_DEFAULT_LEVEL;
4286 level = level_and_flags & 0xF;
4287 store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
4288
4289 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION))
4290 return MZ_FALSE;
4291
4292 pState = pZip->m_pState;
4293
4294 if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
4295 return MZ_FALSE;
4296 // No zip64 support yet
4297 if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
4298 return MZ_FALSE;
4299 if (!mz_zip_writer_validate_archive_name(pArchive_name))
4300 return MZ_FALSE;
4301
4302#ifndef MINIZ_NO_TIME
4303 {
4304 time_t cur_time; time(&cur_time);
4305 mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date);
4306 }
4307#endif // #ifndef MINIZ_NO_TIME
4308
4309 archive_name_size = strlen(pArchive_name);
4310 if (archive_name_size > 0xFFFF)
4311 return MZ_FALSE;
4312
4313 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
4314
4315 // no zip64 support yet
4316 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
4317 return MZ_FALSE;
4318
4319 if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
4320 {
4321 // Set DOS Subdirectory attribute bit.
4322 ext_attributes |= 0x10;
4323 // Subdirectories cannot contain data.
4324 if ((buf_size) || (uncomp_size))
4325 return MZ_FALSE;
4326 }
4327
4328 // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.)
4329 if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
4330 return MZ_FALSE;
4331
4332 if ((!store_data_uncompressed) && (buf_size))
4333 {
4334 if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
4335 return MZ_FALSE;
4336 }
4337
4338 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
4339 {
4340 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4341 return MZ_FALSE;
4342 }
4343 local_dir_header_ofs += num_alignment_padding_bytes;
4344 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
4345 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
4346
4347 MZ_CLEAR_OBJ(local_dir_header);
4348 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
4349 {
4350 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4351 return MZ_FALSE;
4352 }
4353 cur_archive_file_ofs += archive_name_size;
4354
4355 if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
4356 {
4357 uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size);
4358 uncomp_size = buf_size;
4359 if (uncomp_size <= 3)
4360 {
4361 level = 0;
4362 store_data_uncompressed = MZ_TRUE;
4363 }
4364 }
4365
4366 if (store_data_uncompressed)
4367 {
4368 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
4369 {
4370 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4371 return MZ_FALSE;
4372 }
4373
4374 cur_archive_file_ofs += buf_size;
4375 comp_size = buf_size;
4376
4377 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
4378 method = MZ_DEFLATED;
4379 }
4380 else if (buf_size)
4381 {
4382 mz_zip_writer_add_state state;
4383
4384 state.m_pZip = pZip;
4385 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
4386 state.m_comp_size = 0;
4387
4388 if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ||
4389 (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
4390 {
4391 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4392 return MZ_FALSE;
4393 }
4394
4395 comp_size = state.m_comp_size;
4396 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
4397
4398 method = MZ_DEFLATED;
4399 }
4400
4401 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4402 pComp = NULL;
4403
4404 // no zip64 support yet
4405 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
4406 return MZ_FALSE;
4407
4408 if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
4409 return MZ_FALSE;
4410
4411 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
4412 return MZ_FALSE;
4413
4414 if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
4415 return MZ_FALSE;
4416
4417 pZip->m_total_files++;
4418 pZip->m_archive_size = cur_archive_file_ofs;
4419
4420 return MZ_TRUE;
4421}
4422
4423#ifndef MINIZ_NO_STDIO
4424mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
4425{
4426 mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
4427 mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
4428 mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = 0, comp_size = 0;
4429 size_t archive_name_size;
4430 mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
4431 MZ_FILE *pSrc_file = NULL;
4432
4433 if ((int)level_and_flags < 0)
4434 level_and_flags = MZ_DEFAULT_LEVEL;
4435 level = level_and_flags & 0xF;
4436
4437 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
4438 return MZ_FALSE;
4439 if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
4440 return MZ_FALSE;
4441 if (!mz_zip_writer_validate_archive_name(pArchive_name))
4442 return MZ_FALSE;
4443
4444 archive_name_size = strlen(pArchive_name);
4445 if (archive_name_size > 0xFFFF)
4446 return MZ_FALSE;
4447
4448 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
4449
4450 // no zip64 support yet
4451 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF))
4452 return MZ_FALSE;
4453
4454 if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date))
4455 return MZ_FALSE;
4456
4457 pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
4458 if (!pSrc_file)
4459 return MZ_FALSE;
4460 MZ_FSEEK64(pSrc_file, 0, SEEK_END);
4461 uncomp_size = MZ_FTELL64(pSrc_file);
4462 MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
4463
4464 if (uncomp_size > 0xFFFFFFFF)
4465 {
4466 // No zip64 support yet
4467 MZ_FCLOSE(pSrc_file);
4468 return MZ_FALSE;
4469 }
4470 if (uncomp_size <= 3)
4471 level = 0;
4472
4473 if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header)))
4474 {
4475 MZ_FCLOSE(pSrc_file);
4476 return MZ_FALSE;
4477 }
4478 local_dir_header_ofs += num_alignment_padding_bytes;
4479 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
4480 cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header);
4481
4482 MZ_CLEAR_OBJ(local_dir_header);
4483 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
4484 {
4485 MZ_FCLOSE(pSrc_file);
4486 return MZ_FALSE;
4487 }
4488 cur_archive_file_ofs += archive_name_size;
4489
4490 if (uncomp_size)
4491 {
4492 mz_uint64 uncomp_remaining = uncomp_size;
4493 void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
4494 if (!pRead_buf)
4495 {
4496 MZ_FCLOSE(pSrc_file);
4497 return MZ_FALSE;
4498 }
4499
4500 if (!level)
4501 {
4502 while (uncomp_remaining)
4503 {
4504 mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
4505 if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))
4506 {
4507 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4508 MZ_FCLOSE(pSrc_file);
4509 return MZ_FALSE;
4510 }
4511 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
4512 uncomp_remaining -= n;
4513 cur_archive_file_ofs += n;
4514 }
4515 comp_size = uncomp_size;
4516 }
4517 else
4518 {
4519 mz_bool result = MZ_FALSE;
4520 mz_zip_writer_add_state state;
4521 tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
4522 if (!pComp)
4523 {
4524 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4525 MZ_FCLOSE(pSrc_file);
4526 return MZ_FALSE;
4527 }
4528
4529 state.m_pZip = pZip;
4530 state.m_cur_archive_file_ofs = cur_archive_file_ofs;
4531 state.m_comp_size = 0;
4532
4533 if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY)
4534 {
4535 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4536 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4537 MZ_FCLOSE(pSrc_file);
4538 return MZ_FALSE;
4539 }
4540
4541 for ( ; ; )
4542 {
4543 size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE);
4544 tdefl_status status;
4545
4546 if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
4547 break;
4548
4549 uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
4550 uncomp_remaining -= in_buf_size;
4551
4552 status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH);
4553 if (status == TDEFL_STATUS_DONE)
4554 {
4555 result = MZ_TRUE;
4556 break;
4557 }
4558 else if (status != TDEFL_STATUS_OKAY)
4559 break;
4560 }
4561
4562 pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
4563
4564 if (!result)
4565 {
4566 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4567 MZ_FCLOSE(pSrc_file);
4568 return MZ_FALSE;
4569 }
4570
4571 comp_size = state.m_comp_size;
4572 cur_archive_file_ofs = state.m_cur_archive_file_ofs;
4573
4574 method = MZ_DEFLATED;
4575 }
4576
4577 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
4578 }
4579
4580 MZ_FCLOSE(pSrc_file); pSrc_file = NULL;
4581
4582 // no zip64 support yet
4583 if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF))
4584 return MZ_FALSE;
4585
4586 if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date))
4587 return MZ_FALSE;
4588
4589 if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
4590 return MZ_FALSE;
4591
4592 if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes))
4593 return MZ_FALSE;
4594
4595 pZip->m_total_files++;
4596 pZip->m_archive_size = cur_archive_file_ofs;
4597
4598 return MZ_TRUE;
4599}
4600#endif // #ifndef MINIZ_NO_STDIO
4601
4602mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index)
4603{
4604 mz_uint n, bit_flags, num_alignment_padding_bytes;
4605 mz_uint64 comp_bytes_remaining, local_dir_header_ofs;
4606 mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
4607 mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
4608 mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
4609 size_t orig_central_dir_size;
4610 mz_zip_internal_state *pState;
4611 void *pBuf; const mz_uint8 *pSrc_central_header;
4612
4613 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
4614 return MZ_FALSE;
4615 if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index)))
4616 return MZ_FALSE;
4617 pState = pZip->m_pState;
4618
4619 num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
4620
4621 // no zip64 support yet
4622 if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
4623 return MZ_FALSE;
4624
4625 cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
4626 cur_dst_file_ofs = pZip->m_archive_size;
4627
4628 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
4629 return MZ_FALSE;
4630 if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
4631 return MZ_FALSE;
4632 cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
4633
4634 if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
4635 return MZ_FALSE;
4636 cur_dst_file_ofs += num_alignment_padding_bytes;
4637 local_dir_header_ofs = cur_dst_file_ofs;
4638 if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); }
4639
4640 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
4641 return MZ_FALSE;
4642 cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
4643
4644 n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
4645 comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
4646
4647 if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining)))))
4648 return MZ_FALSE;
4649
4650 while (comp_bytes_remaining)
4651 {
4652 n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining);
4653 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
4654 {
4655 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4656 return MZ_FALSE;
4657 }
4658 cur_src_file_ofs += n;
4659
4660 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
4661 {
4662 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4663 return MZ_FALSE;
4664 }
4665 cur_dst_file_ofs += n;
4666
4667 comp_bytes_remaining -= n;
4668 }
4669
4670 bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
4671 if (bit_flags & 8)
4672 {
4673 // Copy data descriptor
4674 if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
4675 {
4676 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4677 return MZ_FALSE;
4678 }
4679
4680 n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3);
4681 if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
4682 {
4683 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4684 return MZ_FALSE;
4685 }
4686
4687 cur_src_file_ofs += n;
4688 cur_dst_file_ofs += n;
4689 }
4690 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
4691
4692 // no zip64 support yet
4693 if (cur_dst_file_ofs > 0xFFFFFFFF)
4694 return MZ_FALSE;
4695
4696 orig_central_dir_size = pState->m_central_dir.m_size;
4697
4698 memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
4699 MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
4700 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
4701 return MZ_FALSE;
4702
4703 n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
4704 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n))
4705 {
4706 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4707 return MZ_FALSE;
4708 }
4709
4710 if (pState->m_central_dir.m_size > 0xFFFFFFFF)
4711 return MZ_FALSE;
4712 n = (mz_uint32)orig_central_dir_size;
4713 if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
4714 {
4715 mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
4716 return MZ_FALSE;
4717 }
4718
4719 pZip->m_total_files++;
4720 pZip->m_archive_size = cur_dst_file_ofs;
4721
4722 return MZ_TRUE;
4723}
4724
4725mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
4726{
4727 mz_zip_internal_state *pState;
4728 mz_uint64 central_dir_ofs, central_dir_size;
4729 mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE];
4730
4731 if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
4732 return MZ_FALSE;
4733
4734 pState = pZip->m_pState;
4735
4736 // no zip64 support yet
4737 if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF))
4738 return MZ_FALSE;
4739
4740 central_dir_ofs = 0;
4741 central_dir_size = 0;
4742 if (pZip->m_total_files)
4743 {
4744 // Write central directory
4745 central_dir_ofs = pZip->m_archive_size;
4746 central_dir_size = pState->m_central_dir.m_size;
4747 pZip->m_central_directory_file_ofs = central_dir_ofs;
4748 if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)
4749 return MZ_FALSE;
4750 pZip->m_archive_size += central_dir_size;
4751 }
4752
4753 // Write end of central directory record
4754 MZ_CLEAR_OBJ(hdr);
4755 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
4756 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
4757 MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
4758 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size);
4759 MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs);
4760
4761 if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr))
4762 return MZ_FALSE;
4763#ifndef MINIZ_NO_STDIO
4764 if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
4765 return MZ_FALSE;
4766#endif // #ifndef MINIZ_NO_STDIO
4767
4768 pZip->m_archive_size += sizeof(hdr);
4769
4770 pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
4771 return MZ_TRUE;
4772}
4773
4774mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize)
4775{
4776 if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize))
4777 return MZ_FALSE;
4778 if (pZip->m_pWrite != mz_zip_heap_write_func)
4779 return MZ_FALSE;
4780 if (!mz_zip_writer_finalize_archive(pZip))
4781 return MZ_FALSE;
4782
4783 *pBuf = pZip->m_pState->m_pMem;
4784 *pSize = pZip->m_pState->m_mem_size;
4785 pZip->m_pState->m_pMem = NULL;
4786 pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
4787 return MZ_TRUE;
4788}
4789
4790mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
4791{
4792 mz_zip_internal_state *pState;
4793 mz_bool status = MZ_TRUE;
4794 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
4795 return MZ_FALSE;
4796
4797 pState = pZip->m_pState;
4798 pZip->m_pState = NULL;
4799 mz_zip_array_clear(pZip, &pState->m_central_dir);
4800 mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
4801 mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
4802
4803#ifndef MINIZ_NO_STDIO
4804 if (pState->m_pFile)
4805 {
4806 MZ_FCLOSE(pState->m_pFile);
4807 pState->m_pFile = NULL;
4808 }
4809#endif // #ifndef MINIZ_NO_STDIO
4810
4811 if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
4812 {
4813 pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
4814 pState->m_pMem = NULL;
4815 }
4816
4817 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
4818 pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
4819 return status;
4820}
4821
4822#ifndef MINIZ_NO_STDIO
4823mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
4824{
4825 mz_bool status, created_new_archive = MZ_FALSE;
4826 mz_zip_archive zip_archive;
4827 struct MZ_FILE_STAT_STRUCT file_stat;
4828 MZ_CLEAR_OBJ(zip_archive);
4829 if ((int)level_and_flags < 0)
4830 level_and_flags = MZ_DEFAULT_LEVEL;
4831 if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
4832 return MZ_FALSE;
4833 if (!mz_zip_writer_validate_archive_name(pArchive_name))
4834 return MZ_FALSE;
4835 if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
4836 {
4837 // Create a new archive.
4838 if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0))
4839 return MZ_FALSE;
4840 created_new_archive = MZ_TRUE;
4841 }
4842 else
4843 {
4844 // Append to an existing archive.
4845 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
4846 return MZ_FALSE;
4847 if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename))
4848 {
4849 mz_zip_reader_end(&zip_archive);
4850 return MZ_FALSE;
4851 }
4852 }
4853 status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
4854 // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.)
4855 if (!mz_zip_writer_finalize_archive(&zip_archive))
4856 status = MZ_FALSE;
4857 if (!mz_zip_writer_end(&zip_archive))
4858 status = MZ_FALSE;
4859 if ((!status) && (created_new_archive))
4860 {
4861 // It's a new archive and something went wrong, so just delete it.
4862 int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
4863 (void)ignoredStatus;
4864 }
4865 return status;
4866}
4867
4868void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
4869{
4870 int file_index;
4871 mz_zip_archive zip_archive;
4872 void *p = NULL;
4873
4874 if (pSize)
4875 *pSize = 0;
4876
4877 if ((!pZip_filename) || (!pArchive_name))
4878 return NULL;
4879
4880 MZ_CLEAR_OBJ(zip_archive);
4881 if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY))
4882 return NULL;
4883
4884 if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0)
4885 p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
4886
4887 mz_zip_reader_end(&zip_archive);
4888 return p;
4889}
4890
4891#endif // #ifndef MINIZ_NO_STDIO
4892
4893#endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
4894
4895#endif // #ifndef MINIZ_NO_ARCHIVE_APIS
4896
4897#ifdef __cplusplus
4898}
4899#endif
4900
4901#endif // MINIZ_HEADER_FILE_ONLY
4902
4903/*
4904 This is free and unencumbered software released into the public domain.
4905
4906 Anyone is free to copy, modify, publish, use, compile, sell, or
4907 distribute this software, either in source code form or as a compiled
4908 binary, for any purpose, commercial or non-commercial, and by any
4909 means.
4910
4911 In jurisdictions that recognize copyright laws, the author or authors
4912 of this software dedicate any and all copyright interest in the
4913 software to the public domain. We make this dedication for the benefit
4914 of the public at large and to the detriment of our heirs and
4915 successors. We intend this dedication to be an overt act of
4916 relinquishment in perpetuity of all present and future rights to this
4917 software under copyright law.
4918
4919 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
4920 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
4921 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
4922 IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
4923 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
4924 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
4925 OTHER DEALINGS IN THE SOFTWARE.
4926
4927 For more information, please refer to <http://unlicense.org/>
4928*/
diff --git a/apps/plugins/xrick/README.md b/apps/plugins/xrick/README.md
new file mode 100644
index 0000000000..ecb4c19b50
--- /dev/null
+++ b/apps/plugins/xrick/README.md
@@ -0,0 +1,88 @@
1xrick
2=====
3
4xrick is a clone of [Rick Dangerous](http://en.wikipedia.org/wiki/Rick_Dangerous),
5known to run on Linux, Windows, BeOs, Amiga, QNX, all sorts of gaming consoles...
6
7License agreement & legal bable
8-------------------------------
9
10* Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net) (http://www.bigorno.net/xrick/)
11* Copyright (C) 2008-2014 Pierluigi Vicinanza (pierluigi DOT vicinanza AT gmail.com)
12
13I (BigOrno) have written the initial [xrick](http://www.bigorno.net/xrick/) code.
14However, graphics and maps and sounds are by the authors of the original Rick Dangerous
15game, and "Rick Dangerous" remains a trademark of its owner(s) -- maybe
16Core Design (who wrote the game) or FireBird (who published it).
17As of today, I have not been successful at contacting Core Design.
18
19This makes it a bit difficult to formally release the whole code,
20including data for graphics and maps and sounds, under the terms of
21licences such as the GNU General Public Licence. So the code is
22released "in the spirit" of the GNU GPL. Whatever that means.
23
24This program is distributed in the hope that it will be useful, but
25WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
26or FITNESS FOR A PARTICULAR PURPOSE.
27
28Building
29--------
30
31**Requirements:**
32
33* [CMake](http://www.cmake.org/)
34* [SDL](https://www.libsdl.org/download-1.2.php) version 1.2.x
35* [zlib](http://www.zlib.net/)
36
371. *Create a build directory*
38
39 ```
40 $ cd xrick-x.x.x
41 $ mkdir build
42 $ cd build
43 ```
44
452. *Generate your Makefile*
46
47 `$ cmake ../source/xrick/projects/cmake`
48
493. *Build*
50
51 `$ make`
52
534. *Install (optional)*
54
55 `$ make install`
56
57Platform specific notes can be found in README.platforms.
58
59Usage
60-----
61
62`xrick --help` will tell you all about command-line options.
63
64Controls
65--------
66
67- left, right, up (jump) or down (crawl): arrow keys or Z, X, O and K.
68- fire: SPACE, end: E, pause: P, exit: ESC.
69- use left, right, up, down + fire to poke something with your stick,
70 lay a stick of dynamite, or fire a bullet.
71- toggle fullscreen: F1 ; zoom in/out: F2, F3.
72- mute: F4 ; volume up/down: F5, F6.
73- cheat modes, "trainer": F7 ; "never die": F8 ; "expose": F9.
74
75More details at http://www.bigorno.net/xrick/
76
77Release History
78---------------
79
80Please see the file called CHANGELOG.md.
81
82Contacts
83--------
84
85Report problems or ask questions to:
86
87* _BigOrno_ (bigorno@bigorno.net)
88* _Pierluigi Vicinanza_ (pierluigi DOT vicinanza AT gmail.com)
diff --git a/apps/plugins/xrick/README.rockbox b/apps/plugins/xrick/README.rockbox
new file mode 100644
index 0000000000..fe6bcd2fd3
--- /dev/null
+++ b/apps/plugins/xrick/README.rockbox
@@ -0,0 +1,16 @@
1xrick on Rockbox
2----------------
3
4Based on the upstream #021212 release.
5
6Currently enabled on all players that have at least 2-bit (ie greyscale)
7display, but is optimized for color displays of 320x200 or larger.
8
9You will need the data files extracted into your player's root
10directory. For example:
11
12 $ unzip xrick-data.zip -d /mnt/myMp3Player
13
14Note that most players do not have a tuned keymap for xrick, instead
15relying on the standard "pluginlib" bindings that are most likely
16sub-optimal. Patches welcome!
diff --git a/apps/plugins/xrick/SOURCES b/apps/plugins/xrick/SOURCES
new file mode 100644
index 0000000000..f3acdd541a
--- /dev/null
+++ b/apps/plugins/xrick/SOURCES
@@ -0,0 +1,40 @@
1control.c
2devtools.c
3draw.c
4e_bomb.c
5e_bonus.c
6e_box.c
7e_bullet.c
8e_rick.c
9e_sbonus.c
10e_them.c
11ents.c
12game.c
13maps.c
14rects.c
15res_magic.c
16resources.c
17scr_gameover.c
18scr_getname.c
19scr_imain.c
20scr_imap.c
21scr_pause.c
22scr_xrick.c
23scroller.c
24util.c
25
26data/img.c
27data/pics.c
28data/sounds.c
29data/sprites.c
30data/tiles.c
31
32system/main_rockbox.c
33system/sysarg_rockbox.c
34system/sysevt_rockbox.c
35system/sysfile_rockbox.c
36system/sysmem_rockbox.c
37system/sysmenu_rockbox.c
38system/syssnd_rockbox.c
39system/system_rockbox.c
40system/sysvid_rockbox.c
diff --git a/apps/plugins/xrick/config.h b/apps/plugins/xrick/config.h
new file mode 100644
index 0000000000..31ecc79bb7
--- /dev/null
+++ b/apps/plugins/xrick/config.h
@@ -0,0 +1,58 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#ifndef XRICK_CONFIG_H
26#define XRICK_CONFIG_H
27
28/* graphics (choose one) */
29#define GFXST
30#undef GFXPC
31
32/* sound support */
33#define ENABLE_SOUND
34
35/* cheats support */
36#define ENABLE_CHEATS
37
38/* development tools */
39#undef ENABLE_DEVTOOLS
40
41/* Print debug info to screen */
42#undef ENABLE_SYSPRINTF_TO_SCREEN
43
44/* enable/disable subsystem debug */
45#undef DEBUG_MEMORY
46#undef DEBUG_ENTS
47#undef DEBUG_SCROLLER
48#undef DEBUG_MAPS
49#undef DEBUG_JOYSTICK
50#undef DEBUG_EVENTS
51#undef DEBUG_AUDIO
52#undef DEBUG_AUDIO2
53#undef DEBUG_VIDEO
54#undef DEBUG_VIDEO2
55
56#endif /* ndef XRICK_CONFIG_H */
57
58/* eof */
diff --git a/apps/plugins/xrick/control.c b/apps/plugins/xrick/control.c
new file mode 100644
index 0000000000..27fbe97376
--- /dev/null
+++ b/apps/plugins/xrick/control.c
@@ -0,0 +1,24 @@
1/*
2 * xrick/control.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/control.h"
17
18unsigned control_status = 0;
19extern inline bool control_test(control_t c);
20extern inline void control_set(control_t c);
21extern inline void control_clear(control_t c);
22bool control_active = true;
23
24/* eof */
diff --git a/apps/plugins/xrick/control.h b/apps/plugins/xrick/control.h
new file mode 100644
index 0000000000..91d0a8a195
--- /dev/null
+++ b/apps/plugins/xrick/control.h
@@ -0,0 +1,41 @@
1/*
2 * xrick/control.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _CONTROL_H
17#define _CONTROL_H
18
19#include "xrick/system/basic_types.h"
20
21typedef enum
22{
23 Control_UP = (1 << 0),
24 Control_DOWN = (1 << 1),
25 Control_LEFT = (1 << 2),
26 Control_RIGHT = (1 << 3),
27 Control_PAUSE = (1 << 4),
28 Control_END = (1 << 5),
29 Control_EXIT = (1 << 6),
30 Control_FIRE = (1 << 7)
31} control_t;
32
33extern unsigned control_status;
34inline bool control_test(control_t c) { return control_status & c; }
35inline void control_set(control_t c) { control_status |= c; }
36inline void control_clear(control_t c) { control_status &= ~c; }
37extern bool control_active;
38
39#endif /* ndef _CONTROL_H */
40
41/* eof */
diff --git a/apps/plugins/xrick/data/img.c b/apps/plugins/xrick/data/img.c
new file mode 100644
index 0000000000..2226df3c48
--- /dev/null
+++ b/apps/plugins/xrick/data/img.c
@@ -0,0 +1,23 @@
1/*
2 * xrick/data/img.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/data/img.h"
15
16#include <stddef.h> /* NULL */
17
18/*
19 * globals
20 */
21img_t *img_splash = NULL;
22
23/* eof */
diff --git a/apps/plugins/xrick/data/img.h b/apps/plugins/xrick/data/img.h
new file mode 100644
index 0000000000..96952627f9
--- /dev/null
+++ b/apps/plugins/xrick/data/img.h
@@ -0,0 +1,39 @@
1/*
2 * xrick/data/img.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _IMG_H
17#define _IMG_H
18
19#include "xrick/system/basic_types.h"
20
21typedef struct {
22 U8 r, g, b, nothing;
23} img_color_t;
24
25typedef struct {
26 U16 width;
27 U16 height;
28 U16 xPos;
29 U16 yPos;
30 U16 ncolors;
31 img_color_t *colors;
32 U8 *pixels;
33} img_t;
34
35extern img_t *img_splash;
36
37#endif /* ndef _IMG_H */
38
39/* eof */
diff --git a/apps/plugins/xrick/data/pics.c b/apps/plugins/xrick/data/pics.c
new file mode 100644
index 0000000000..103bfd8344
--- /dev/null
+++ b/apps/plugins/xrick/data/pics.c
@@ -0,0 +1,29 @@
1/*
2 * xrick/data/pics.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/data/pics.h"
15
16#ifdef GFXST
17
18#include <stddef.h> /* NULL */
19
20/*
21 * globals
22 */
23pic_t *pic_haf = NULL;
24pic_t *pic_congrats = NULL;
25pic_t *pic_splash = NULL;
26
27#endif /* GFXST */
28
29/* eof */
diff --git a/apps/plugins/xrick/data/pics.h b/apps/plugins/xrick/data/pics.h
new file mode 100644
index 0000000000..0c540b125e
--- /dev/null
+++ b/apps/plugins/xrick/data/pics.h
@@ -0,0 +1,41 @@
1/*
2 * xrick/data/pics.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _PICS_H
17#define _PICS_H
18
19#include "xrick/config.h"
20
21#ifdef GFXST
22
23#include "xrick/system/basic_types.h"
24
25typedef struct {
26 U16 width;
27 U16 height;
28 U16 xPos;
29 U16 yPos;
30 U32 *pixels;
31} pic_t;
32
33extern pic_t *pic_haf;
34extern pic_t *pic_congrats;
35extern pic_t *pic_splash;
36
37#endif /* GFXST */
38
39#endif /* ndef _PICS_H */
40
41/* eof */
diff --git a/apps/plugins/xrick/data/sounds.c b/apps/plugins/xrick/data/sounds.c
new file mode 100644
index 0000000000..853e7cd198
--- /dev/null
+++ b/apps/plugins/xrick/data/sounds.c
@@ -0,0 +1,44 @@
1/*
2 * xrick/data/sounds.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/data/sounds.h"
15
16#ifdef ENABLE_SOUND
17
18#include <stddef.h> /* NULL */
19
20sound_t *soundBombshht = NULL;
21sound_t *soundBonus = NULL;
22sound_t *soundBox = NULL;
23sound_t *soundBullet = NULL;
24sound_t *soundCrawl = NULL;
25sound_t *soundDie = NULL;
26sound_t *soundEntity[SOUNDS_NBR_ENTITIES];
27sound_t *soundExplode = NULL;
28sound_t *soundGameover = NULL;
29sound_t *soundJump = NULL;
30sound_t *soundPad = NULL;
31sound_t *soundSbonus1 = NULL;
32sound_t *soundSbonus2 = NULL;
33sound_t *soundStick = NULL;
34sound_t *soundTune0 = NULL;
35sound_t *soundTune1 = NULL;
36sound_t *soundTune2 = NULL;
37sound_t *soundTune3 = NULL;
38sound_t *soundTune4 = NULL;
39sound_t *soundTune5 = NULL;
40sound_t *soundWalk = NULL;
41
42#endif /* ENABLE_SOUND */
43
44/* eof */ \ No newline at end of file
diff --git a/apps/plugins/xrick/data/sounds.h b/apps/plugins/xrick/data/sounds.h
new file mode 100644
index 0000000000..5d89b3e9ee
--- /dev/null
+++ b/apps/plugins/xrick/data/sounds.h
@@ -0,0 +1,87 @@
1/*
2 * xrick/data/sounds.h
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#ifndef _SOUNDS_H
15#define _SOUNDS_H
16
17#include "xrick/config.h"
18
19#ifdef ENABLE_SOUND
20
21#include "xrick/system/basic_types.h"
22
23typedef struct {
24 char *name;
25 U8 *buf;
26 U32 len;
27 bool dispose;
28} sound_t;
29
30enum
31{
32 /* expected format is 8-bit mono at 22050Hz */
33 Wave_SAMPLE_RATE = 22050,
34 Wave_AUDIO_FORMAT = 1, /* PCM = 1 (i.e. Linear quantization) */
35 Wave_CHANNEL_COUNT = 1,
36 Wave_BITS_PER_SAMPLE = 8,
37};
38
39typedef struct {
40 /* "RIFF" chunk descriptor */
41 U8 riffChunkId[4];
42 U8 riffChunkSize[4];
43 U8 riffType[4];
44 /* "fmt" sub-chunk */
45 U8 formatChunkId[4];
46 U8 formatChunkSize[4];
47 U8 audioFormat[2];
48 U8 channelCount[2];
49 U8 sampleRate[4];
50 U8 byteRate[4];
51 U8 blockAlign[2];
52 U8 bitsPerSample[2];
53 /* "data" sub-chunk */
54 U8 dataChunkId[4];
55 U8 dataChunkSize[4];
56} wave_header_t;
57
58/* apparently there are 10 entity sounds in original game (ref. "e_them.c" notes)? However we only have 9 so far... */
59enum { SOUNDS_NBR_ENTITIES = 10 };
60
61extern sound_t *soundBombshht;
62extern sound_t *soundBonus;
63extern sound_t *soundBox;
64extern sound_t *soundBullet;
65extern sound_t *soundCrawl;
66extern sound_t *soundDie;
67extern sound_t *soundEntity[SOUNDS_NBR_ENTITIES];
68extern sound_t *soundExplode;
69extern sound_t *soundGameover;
70extern sound_t *soundJump;
71extern sound_t *soundPad;
72extern sound_t *soundSbonus1;
73extern sound_t *soundSbonus2;
74extern sound_t *soundStick;
75extern sound_t *soundTune0;
76extern sound_t *soundTune1;
77extern sound_t *soundTune2;
78extern sound_t *soundTune3;
79extern sound_t *soundTune4;
80extern sound_t *soundTune5;
81extern sound_t *soundWalk;
82
83#endif /* ENABLE_SOUND */
84
85#endif /* ndef _SOUNDS_H */
86
87/* eof */ \ No newline at end of file
diff --git a/apps/plugins/xrick/data/sprites.c b/apps/plugins/xrick/data/sprites.c
new file mode 100644
index 0000000000..461861e85e
--- /dev/null
+++ b/apps/plugins/xrick/data/sprites.c
@@ -0,0 +1,22 @@
1/*
2 * xrick/data/sprites.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/data/sprites.h"
15
16/*
17 * globals
18 */
19size_t sprites_nbr_sprites = 0;
20sprite_t *sprites_data = NULL;
21
22/* eof */
diff --git a/apps/plugins/xrick/data/sprites.h b/apps/plugins/xrick/data/sprites.h
new file mode 100644
index 0000000000..124ad4bc85
--- /dev/null
+++ b/apps/plugins/xrick/data/sprites.h
@@ -0,0 +1,70 @@
1/*
2 * xrick/data/sprites.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16/*
17 * NOTES -- PC version
18 *
19 * A sprite consists in 4 columns and 21 rows of (U16 mask, U16 pict),
20 * each pair representing 8 pixels (cga encoding, two bits per pixels).
21 * Sprites are stored in 'sprites.bin' and are loaded by spr_init. Memory
22 * is freed by spr_shutdown.
23 *
24 * There are four sprites planes. Plane 0 is the raw content of 'sprites.bin',
25 * and planes 1, 2 and 3 contain copies of plane 0 with all sprites shifted
26 * 2, 4 and 6 pixels to the right.
27 */
28
29#ifndef _SPRITES_H_
30#define _SPRITES_H_
31
32#include "xrick/config.h"
33
34#include "xrick/system/basic_types.h"
35
36#include <stddef.h> /* size_t */
37
38#ifdef GFXPC
39
40typedef struct {
41 U16 mask;
42 U16 pict;
43} spriteX_t;
44
45enum {
46 SPRITES_NBR_ROWS = 21,
47 SPRITES_NBR_COLS = 4
48};
49typedef spriteX_t sprite_t[SPRITES_NBR_COLS][SPRITES_NBR_ROWS]; /* one sprite */
50
51#endif /* GFXPC */
52
53
54#ifdef GFXST
55
56enum {
57 SPRITES_NBR_ROWS = 21,
58 SPRITES_NBR_COLS = 4,
59 SPRITES_NBR_DATA = SPRITES_NBR_ROWS * SPRITES_NBR_COLS
60};
61typedef U32 sprite_t[SPRITES_NBR_DATA];
62
63#endif /* GFXST */
64
65extern size_t sprites_nbr_sprites;
66extern sprite_t *sprites_data;
67
68#endif /* ndef _SPRITES_H_ */
69
70/* eof */
diff --git a/apps/plugins/xrick/data/tiles.c b/apps/plugins/xrick/data/tiles.c
new file mode 100644
index 0000000000..17d702ee6b
--- /dev/null
+++ b/apps/plugins/xrick/data/tiles.c
@@ -0,0 +1,22 @@
1/*
2 * xrick/data/tiles.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/data/tiles.h"
15
16/*
17 * globals
18 */
19size_t tiles_nbr_banks = 0;
20tile_t *tiles_data = NULL;
21
22/* eof */
diff --git a/apps/plugins/xrick/data/tiles.h b/apps/plugins/xrick/data/tiles.h
new file mode 100644
index 0000000000..35bc07184e
--- /dev/null
+++ b/apps/plugins/xrick/data/tiles.h
@@ -0,0 +1,70 @@
1/*
2 * xrick/data/tiles.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16/*
17 * NOTES
18 *
19 * A tile consists in one column and 8 rows of 8 U16 (cga encoding, two
20 * bits per pixel). The tl_tiles array contains all tiles, with the
21 * following structure:
22 *
23 * 0x0000 - 0x00FF tiles for main intro
24 * 0x0100 - 0x01FF tiles for map intro
25 * 0x0200 - 0x0327 unused
26 * 0x0328 - 0x0427 game tiles, page 0
27 * 0x0428 - 0x0527 game tiles, page 1
28 * 0x0527 - 0x05FF unused
29 */
30
31#ifndef _TILES_H
32#define _TILES_H
33
34#include "xrick/system/basic_types.h"
35
36#include "xrick/config.h"
37
38#include <stddef.h> /* size_t */
39
40/*
41 * three special tile numbers
42 */
43enum {
44 TILES_BULLET = 0x01,
45 TILES_BOMB = 0x02,
46 TILES_RICK = 0x03
47};
48
49/*
50 * one single tile
51 */
52enum { TILES_NBR_LINES = 0x08 };
53
54#ifdef GFXPC
55typedef U16 tile_t[TILES_NBR_LINES];
56#endif
57#ifdef GFXST
58typedef U32 tile_t[TILES_NBR_LINES];
59#endif
60
61/*
62 * tiles banks (each bank is 0x100 tiles)
63 */
64enum { TILES_NBR_TILES = 0x100 };
65extern size_t tiles_nbr_banks;
66extern tile_t *tiles_data;
67
68#endif /* ndef _TILES_H */
69
70/* eof */
diff --git a/apps/plugins/xrick/debug.h b/apps/plugins/xrick/debug.h
new file mode 100644
index 0000000000..5bf777213b
--- /dev/null
+++ b/apps/plugins/xrick/debug.h
@@ -0,0 +1,84 @@
1/*
2 * xrick/debug.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _DEBUG_H
17#define _DEBUG_H
18
19#include "xrick/config.h"
20
21/* define IFDEBUG macros */
22#ifdef DEBUG_MEMORY
23#define IFDEBUG_MEMORY(X); X
24#else
25#define IFDEBUG_MEMORY(X);
26#endif
27
28#ifdef DEBUG_ENTS
29#define IFDEBUG_ENTS(X); X
30#else
31#define IFDEBUG_ENTS(X);
32#endif
33
34#ifdef DEBUG_SCROLLER
35#define IFDEBUG_SCROLLER(X); X
36#else
37#define IFDEBUG_SCROLLER(X);
38#endif
39
40#ifdef DEBUG_MAPS
41#define IFDEBUG_MAPS(X); X
42#else
43#define IFDEBUG_MAPS(X);
44#endif
45
46#ifdef DEBUG_JOYSTICK
47#define IFDEBUG_JOYSTICK(X); X
48#else
49#define IFDEBUG_JOYSTICK(X);
50#endif
51
52#ifdef DEBUG_EVENTS
53#define IFDEBUG_EVENTS(X); X
54#else
55#define IFDEBUG_EVENTS(X);
56#endif
57
58#ifdef DEBUG_AUDIO
59#define IFDEBUG_AUDIO(X); X
60#else
61#define IFDEBUG_AUDIO(X);
62#endif
63
64#ifdef DEBUG_AUDIO2
65#define IFDEBUG_AUDIO2(X); X
66#else
67#define IFDEBUG_AUDIO2(X);
68#endif
69
70#ifdef DEBUG_VIDEO
71#define IFDEBUG_VIDEO(X); X
72#else
73#define IFDEBUG_VIDEO(X);
74#endif
75
76#ifdef DEBUG_VIDEO2
77#define IFDEBUG_VIDEO2(X); X
78#else
79#define IFDEBUG_VIDEO2(X);
80#endif
81
82#endif /* ndef _DEBUG_H */
83
84/* eof */
diff --git a/apps/plugins/xrick/devtools.c b/apps/plugins/xrick/devtools.c
new file mode 100644
index 0000000000..56fd5a7106
--- /dev/null
+++ b/apps/plugins/xrick/devtools.c
@@ -0,0 +1,247 @@
1/*
2 * xrick/devtools.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/config.h"
17
18#ifdef ENABLE_DEVTOOLS
19
20#include "xrick/devtools.h"
21#include "xrick/game.h"
22#include "xrick/control.h"
23#include "xrick/screens.h"
24#include "xrick/draw.h"
25#include "xrick/data/sprites.h"
26#include "xrick/maps.h"
27#include "xrick/system/system.h"
28
29/*
30 * DevTools
31 */
32
33U8
34devtools_run(void)
35{
36 static U8 seq = 0;
37 static U8 pos = 0;
38 static U8 pos2 = 0;
39 U8 i, j, k, l;
40 U8 s[128];
41
42 if (seq == 0) {
43 sysvid_clear();
44 game_rects = &draw_SCREENRECT;
45#ifdef GFXPC
46 draw_filter = 0xffff;
47#endif
48 seq = 1;
49 }
50
51 switch (seq) {
52 case 1: /* draw tiles */
53 sysvid_clear();
54 draw_tilesBank = 0;
55 sys_snprintf(s, sizeof(s), "TILES@BANK@%d\376", pos);
56 draw_setfb(4, 4);
57 draw_tilesListImm(s);
58 k = 0;
59 for (i = 0; i < 0x10; i++) {
60 draw_setfb(80 + i * 0x0a, 14);
61 draw_tile((i<10?0x30:'A'-10) + i);
62 draw_setfb(64, 30 + i * 0x0a);
63 draw_tile((i<10?0x30:'A'-10) + i);
64 }
65 draw_tilesBank = pos;
66 for (i = 0; i < 0x10; i++)
67 for (j = 0; j < 0x10; j++) {
68 draw_setfb(80 + j * 0x0a, 30 + i * 0x0a);
69 draw_tile(k++);
70 }
71 seq = 10;
72 break;
73 case 10: /* wait for key pressed */
74 if (control_test(Control_FIRE))
75 seq = 98;
76 if (control_test(Control_UP))
77 seq = 12;
78 if (control_test(Control_DOWN))
79 seq = 13;
80 if (control_test(Control_RIGHT))
81 seq = 11;
82 break;
83 case 11: /* wait for key released */
84 if (!(control_test(Control_RIGHT))) {
85 pos = 0;
86 seq = 21;
87 }
88 break;
89 case 12: /* wait for key released */
90 if (!(control_test(Control_UP))) {
91 if (pos < 4) pos++;
92 seq = 1;
93 }
94 break;
95 case 13: /* wait for key released */
96 if (!(control_test(Control_DOWN))) {
97 if (pos > 0) pos--;
98 seq = 1;
99 }
100 break;
101 case 21: /* draw sprites */
102 sysvid_clear();
103 draw_tilesBank = 0;
104 sys_snprintf(s, sizeof(s), "SPRITES\376");
105 draw_setfb(4, 4);
106 draw_tilesListImm(s);
107 for (i = 0; i < 8; i++) {
108 draw_setfb(0x08 + 0x20 + i * 0x20, 0x30 - 26);
109 draw_tile((i<10?0x30:'A'-10) + i);
110 draw_setfb(0x08 + 0x20 + i * 0x20, 0x30 - 16);
111 draw_tile((i+8<10?0x30:'A'-10) + i+8);
112 }
113 for (i = 0; i < 4; i++) {
114 k = pos + i * 8;
115 draw_setfb(0x20 - 16, 0x08 + 0x30 + i * 0x20);
116 j = k%16;
117 k /= 16;
118 draw_tile((j<10?0x30:'A'-10) + j);
119 draw_setfb(0x20 - 26, 0x08 + 0x30 + i * 0x20);
120 j = k%16;
121 draw_tile((j<10?0x30:'A'-10) + j);
122 }
123 k = pos;
124 for (i = 0; i < 4; i++)
125 for (j = 0; j < 8; j++) {
126 draw_sprite(k++, 0x20 + j * 0x20, 0x30 + i * 0x20);
127 }
128 seq = 30;
129 break;
130 case 30: /* wait for key pressed */
131 if (control_test(Control_FIRE))
132 seq = 98;
133 if (control_test(Control_UP))
134 seq = 32;
135 if (control_test(Control_DOWN))
136 seq = 33;
137 if (control_test(Control_LEFT))
138 seq = 31;
139 if (control_test(Control_RIGHT))
140 seq = 40;
141 break;
142 case 31: /* wait for key released */
143 if (!(control_test(Control_LEFT))) {
144 pos = 0;
145 seq = 1;
146 }
147 break;
148 case 32: /* wait for key released */
149 if (!(control_test(Control_UP))) {
150 if (pos < sprites_nbr_sprites - 32) pos += 32;
151 seq = 21;
152 }
153 break;
154 case 33: /* wait for key released */
155 if (!(control_test(Control_DOWN))) {
156 if (pos > 0) pos -= 32;
157 seq = 21;
158 }
159 break;
160 case 40:
161 sysvid_clear();
162#ifdef GFXPC
163 if (pos2 == 0) pos2 = 2;
164#endif
165#ifdef GFXST
166 if (pos2 == 0) pos2 = 1;
167#endif
168 sys_snprintf(s, sizeof(s), "BLOCKS@%#04X@TO@%#04X@WITH@BANK@%d\376",
169 pos, pos + 4*8-1, pos2);
170 draw_setfb(4, 4);
171 draw_tilesBank = 0;
172 draw_tilesListImm(s);
173 draw_tilesBank = pos2;
174 for (l = 0; l < 8; l++)
175 for (k = 0; k < 4; k++)
176 for (i = 0; i < 4; i++)
177 for (j = 0; j < 4; j++) {
178 draw_setfb(20 + j * 8 + l * 36, 30 + i * 8 + k * 36);
179 draw_tile(map_blocks[pos + l + k * 8][i * 4 + j]);
180 }
181 seq = 41;
182 break;
183 case 41:
184 if (control_test(Control_FIRE))
185 seq = 98;
186 if (control_test(Control_UP))
187 seq = 42;
188 if (control_test(Control_DOWN))
189 seq = 43;
190 if (control_test(Control_LEFT))
191 seq = 44;
192 if (control_test(Control_PAUSE))
193 seq = 45;
194 break;
195 case 42:
196 if (!(control_test(Control_UP))) {
197 if (pos < map_nbr_blocks - 8*4) pos += 8 * 4;
198 seq = 40;
199 }
200 break;
201 case 43:
202 if (!(control_test(Control_DOWN))) {
203 if (pos > 0) pos -= 8 * 4;
204 seq = 40;
205 }
206 break;
207 case 44:
208 if (!(control_test(Control_LEFT))) {
209 pos = 0;
210 pos2 = 0;
211 seq = 21;
212 }
213 break;
214 case 45:
215 if (!(control_test(Control_PAUSE))) {
216#ifdef GFXPC
217 if (pos2 == 2) pos2 = 3;
218 else pos2 = 2;
219#endif
220#ifdef GFXST
221 if (pos2 == 1) pos2 = 2;
222 else pos2 = 1;
223#endif
224 seq = 40;
225 }
226 break;
227 case 98: /* wait for key released */
228 if (!(control_test(Control_FIRE)))
229 seq = 99;
230 break;
231 }
232
233 if (control_test(Control_EXIT)) /* check for exit request */
234 return SCREEN_EXIT;
235
236 if (seq == 99) { /* we're done */
237 sysvid_clear();
238 seq = 0;
239 return SCREEN_DONE;
240 }
241
242 return SCREEN_RUNNING;
243}
244
245#endif /* ENABLE_DEVTOOLS */
246
247/* eof */
diff --git a/apps/plugins/xrick/devtools.h b/apps/plugins/xrick/devtools.h
new file mode 100644
index 0000000000..e1021bfbcd
--- /dev/null
+++ b/apps/plugins/xrick/devtools.h
@@ -0,0 +1,25 @@
1/*
2 * xrick/devtools.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _DEVTOOLS_H
17#define _DEVTOOLS_H
18
19#include "xrick/system/basic_types.h"
20
21extern U8 devtools_run(void);
22
23#endif /* ndef _DEVTOOLS_H */
24
25/* eof */
diff --git a/apps/plugins/xrick/draw.c b/apps/plugins/xrick/draw.c
new file mode 100644
index 0000000000..a759ed5239
--- /dev/null
+++ b/apps/plugins/xrick/draw.c
@@ -0,0 +1,702 @@
1/*
2 * xrick/draw.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16/*
17 * NOTES
18 *
19 * This is the only file which accesses the video. Anything calling d_*
20 * function should be video-independant.
21 *
22 * draw.c draws into a 320x200 or 0x0140x0xc8 8-bits depth frame buffer,
23 * using the CGA 2 bits color codes. It is up to the video to figure out
24 * how to display the frame buffer. Whatever draw.c does, does not show
25 * until the screen is explicitely refreshed.
26 *
27 * The "screen" is the whole 0x0140 by 0x00c8 screen, coordinates go from
28 * 0x0000,0x0000 to 0x013f,0x00c7.
29 *
30 * The "map" is a 0x0100 by 0x0140 rectangle that represents the active
31 * game area.
32 *
33 * Relative to the screen, the "map" is located at 0x0020,-0x0040 : the
34 * "map" is composed of two hidden 0x0100 by 0x0040 rectangles (one at the
35 * top and one at the bottom) and one visible 0x0100 by 0x00c0 rectangle (in
36 * the middle).
37 *
38 * The "map screen" is the visible rectangle ; it is a 0x0100 by 0xc0
39 * rectangle located at 0x0020,0x00.
40 *
41 * Coordinates can be relative to the screen, the map, or the map screen.
42 *
43 * Coordinates can be expressed in pixels. When relative to the map or the
44 * map screen, they can also be expressed in tiles, the map being composed
45 * of rows of 0x20 tiles of 0x08 by 0x08 pixels.
46 */
47
48#include "xrick/system/system.h"
49
50#include "xrick/game.h"
51#include "xrick/draw.h"
52
53#include "xrick/data/sprites.h"
54#include "xrick/data/tiles.h"
55
56#include "xrick/maps.h"
57#include "xrick/rects.h"
58#include "xrick/data/img.h"
59
60
61/*
62 * counters positions (pixels, screen)
63 */
64#ifdef GFXPC
65#define DRAW_STATUS_SCORE_X 0x28
66#define DRAW_STATUS_LIVES_X 0xE8
67#define DRAW_STATUS_Y 0x08
68#endif
69#define DRAW_STATUS_BULLETS_X 0x68
70#define DRAW_STATUS_BOMBS_X 0xA8
71#ifdef GFXST
72#define DRAW_STATUS_SCORE_X 0x20
73#define DRAW_STATUS_LIVES_X 0xF0
74#define DRAW_STATUS_Y 0
75#endif
76
77
78/*
79 * public vars
80 */
81U8 *draw_tllst; /* pointer to tiles list */
82#ifdef GFXPC
83U16 draw_filter; /* CGA colors filter */
84#endif
85U8 draw_tilesBank; /* tile number offset */
86
87rect_t draw_STATUSRECT = {
88 DRAW_STATUS_SCORE_X, DRAW_STATUS_Y,
89 DRAW_STATUS_LIVES_X + 6 * 8 - DRAW_STATUS_SCORE_X, 8,
90 NULL
91};
92const rect_t draw_SCREENRECT = { 0, 0, SYSVID_WIDTH, SYSVID_HEIGHT, NULL };
93
94size_t game_color_count = 0;
95img_color_t *game_colors = NULL;
96
97/*
98 * private vars
99 */
100static U8 *fb; /* frame buffer pointer */
101
102
103/*
104 * Set the frame buffer pointer
105 *
106 * x, y: position (pixels, screen)
107 */
108void
109draw_setfb(U16 x, U16 y)
110{
111 fb = sysvid_fb + x + y * SYSVID_WIDTH;
112}
113
114
115/*
116 * Clip to map screen
117 *
118 * x, y: position (pixels, map) CHANGED clipped
119 * width, height: dimension CHANGED clipped
120 * return: true if fully clipped, false if still (at least partly) visible
121 */
122bool
123draw_clipms(S16 *x, S16 *y, U16 *width, U16 *height)
124{
125 if (*x < 0) {
126 if (*x + *width < 0)
127 return true;
128 else {
129 *width += *x;
130 *x = 0;
131 }
132 }
133 else {
134 if (*x > 0x0100)
135 return true;
136 else if (*x + *width > 0x0100) {
137 *width = 0x0100 - *x;
138 }
139 }
140
141 if (*y < DRAW_XYMAP_SCRTOP) {
142 if ((*y + *height) < DRAW_XYMAP_SCRTOP)
143 return true;
144 else {
145 *height += *y - DRAW_XYMAP_SCRTOP;
146 *y = DRAW_XYMAP_SCRTOP;
147 }
148 }
149 else {
150 if (*y >= DRAW_XYMAP_HBTOP)
151 return true;
152 else if (*y + *height > DRAW_XYMAP_HBTOP)
153 *height = DRAW_XYMAP_HBTOP - *y;
154 }
155
156 return false;
157}
158
159
160/*
161 * Draw a list of tiles onto the frame buffer
162 * start at position indicated by fb ; at the end of each (sub)list,
163 * perform a "carriage return + line feed" i.e. go back to the initial
164 * position then go down one tile row (8 pixels)
165 *
166 * ASM 1e33
167 * fb: CHANGED (see above)
168 * draw_tllst: CHANGED points to the element following 0xfe/0xff end code
169 */
170void
171draw_tilesList(void)
172{
173 U8 *t;
174
175 t = fb;
176 while (draw_tilesSubList() != 0xFE) { /* draw sub-list */
177 t += 8 * SYSVID_WIDTH; /* go down one tile i.e. 8 lines */
178 fb = t;
179 }
180}
181
182
183/*
184 * Draw a list of tiles onto the frame buffer -- same as draw_tilesList,
185 * but accept an immediate string as parameter. Note that the string needs
186 * to be properly terminated with 0xfe (\376) and 0xff (\377) chars.
187 */
188void
189draw_tilesListImm(U8 *list)
190{
191 draw_tllst = list;
192 draw_tilesList();
193}
194
195
196/*
197 * Draw a sub-list of tiles onto the frame buffer
198 * start at position indicated by fb ; leave fb pointing to the next
199 * tile to the right of the last tile drawn
200 *
201 * ASM 1e41
202 * fpb: CHANGED (see above)
203 * draw_tllst: CHANGED points to the element following 0xfe/0xff end code
204 * returns: end code (0xfe : end of list ; 0xff : end of sub-list)
205 */
206U8
207draw_tilesSubList()
208{
209 U8 i;
210
211 i = *(draw_tllst++);
212 while (i != 0xFF && i != 0xFE) { /* while not end */
213 draw_tile(i); /* draw tile */
214 i = *(draw_tllst++);
215 }
216 return i;
217}
218
219
220/*
221 * Draw a tile
222 * at position indicated by fb ; leave fb pointing to the next tile
223 * to the right of the tile drawn
224 *
225 * ASM 1e6c
226 * tlnbr: tile number
227 * draw_filter: CGA colors filter
228 * fb: CHANGED (see above)
229 */
230void
231draw_tile(U8 tileNumber)
232{
233 U8 i, k, *f;
234
235#ifdef GFXPC
236 U16 x;
237#endif
238
239#ifdef GFXST
240 U32 x;
241#endif
242
243 f = fb; /* frame buffer */
244 for (i = 0; i < TILES_NBR_LINES; i++) { /* for all 8 pixel lines */
245
246#ifdef GFXPC
247 x = tiles_data[draw_tilesBank * TILES_NBR_TILES + tileNumber][i] & draw_filter;
248 /*
249 * tiles / perform the transformation from CGA 2 bits
250 * per pixel to frame buffer 8 bits per pixels
251 */
252 for (k = 8; k--; x >>= 2)
253 f[k] = x & 3;
254 f += SYSVID_WIDTH; /* next line */
255#endif
256
257#ifdef GFXST
258 x = tiles_data[draw_tilesBank * TILES_NBR_TILES + tileNumber][i];
259 /*
260 * tiles / perform the transformation from ST 4 bits
261 * per pixel to frame buffer 8 bits per pixels
262 */
263 for (k = 8; k--; x >>= 4)
264 f[k] = x & 0x0F;
265 f += SYSVID_WIDTH; /* next line */
266#endif
267
268 }
269
270 fb += 8; /* next tile */
271}
272
273/*
274 * Draw a sprite
275 *
276 * ASM 1a09
277 * nbr: sprite number
278 * x, y: sprite position (pixels, screen)
279 * fb: CHANGED
280 */
281#ifdef GFXPC
282void
283draw_sprite(U8 nbr, U16 x, U16 y)
284{
285 U8 i, j, k, *f;
286 U16 xm = 0, xp = 0;
287
288 draw_setfb(x, y);
289
290 for (i = 0; i < SPRITES_NBR_COLS; i++) { /* for each tile column */
291 f = fb; /* frame buffer */
292 for (j = 0; j < SPRITES_NBR_ROWS; j++) { /* for each pixel row */
293 xm = sprites_data[nbr][i][j].mask; /* mask */
294 xp = sprites_data[nbr][i][j].pict; /* picture */
295 /*
296 * sprites / perform the transformation from CGA 2 bits
297 * per pixel to frame buffer 8 bits per pixels
298 */
299 for (k = 8; k--; xm >>= 2, xp >>= 2)
300 f[k] = (f[k] & (xm & 3)) | (xp & 3);
301 f += SYSVID_WIDTH;
302 }
303 fb += 8;
304 }
305}
306#endif
307
308
309/*
310 * Draw a sprite
311 *
312 * foobar
313 */
314#ifdef GFXST
315void
316draw_sprite(U8 number, U16 x, U16 y)
317{
318 U8 i, j, k, *f;
319 U16 g;
320 U32 d;
321
322 draw_setfb(x, y);
323 g = 0;
324 for (i = 0; i < SPRITES_NBR_ROWS; i++) { /* rows */
325 f = fb;
326 for (j = 0; j < SPRITES_NBR_COLS; j++) { /* cols */
327 d = sprites_data[number][g++];
328 for (k = 8; k--; d >>= 4)
329 if (d & 0x0F) f[k] = (f[k] & 0xF0) | (d & 0x0F);
330 f += 8;
331 }
332 fb += SYSVID_WIDTH;
333 }
334}
335#endif
336
337
338/*
339 * Draw a sprite
340 *
341 * NOTE re-using original ST graphics format
342 */
343#ifdef GFXST
344void
345draw_sprite2(U8 number, U16 x, U16 y, bool front)
346{
347 U32 d = 0; /* sprite data */
348 S16 x0, y0; /* clipped x, y */
349 U16 w, h; /* width, height */
350 S16 g, /* sprite data offset*/
351 r, c, /* row, column */
352 i, /* frame buffer shifter */
353 im; /* tile flag shifter */
354 U8 flg; /* tile flag */
355
356 x0 = x;
357 y0 = y;
358 w = SPRITES_NBR_COLS * 8; /* each tile column is 8 pixels */
359 h = SPRITES_NBR_ROWS;
360
361 if (draw_clipms(&x0, &y0, &w, &h)) /* return if not visible */
362 return;
363
364 g = 0;
365 draw_setfb(x0 - DRAW_XYMAP_SCRLEFT, y0 - DRAW_XYMAP_SCRTOP + 8);
366
367 for (r = 0; r < SPRITES_NBR_ROWS; r++) {
368 if (r >= h || y + r < y0) continue;
369
370 i = 0x1f;
371 im = x - (x & 0xfff8);
372 flg = map_eflg[map_map[(y + r) >> 3][(x + 0x1f)>> 3]];
373
374#ifdef ENABLE_CHEATS
375#define LOOP(N, C0, C1) \
376 d = sprites_data[number][g + N]; \
377 for (c = C0; c >= C1; c--, i--, d >>= 4, im--) { \
378 if (im == 0) { \
379 flg = map_eflg[map_map[(y + r) >> 3][(x + c) >> 3]]; \
380 im = 8; \
381 } \
382 if (c >= w || x + c < x0) continue; \
383 if (!front && !game_cheat3 && (flg & MAP_EFLG_FGND)) continue; \
384 if (d & 0x0F) fb[i] = (fb[i] & 0xF0) | (d & 0x0F); \
385 if (game_cheat3) fb[i] |= 0x10; \
386 }
387#else
388#define LOOP(N, C0, C1) \
389 d = sprites_data[number][g + N]; \
390 for (c = C0; c >= C1; c--, i--, d >>= 4, im--) { \
391 if (im == 0) { \
392 flg = map_eflg[map_map[(y + r) >> 3][(x + c) >> 3]]; \
393 im = 8; \
394 } \
395 if (!front && (flg & MAP_EFLG_FGND)) continue; \
396 if (c >= w || x + c < x0) continue; \
397 if (d & 0x0F) fb[i] = (fb[i] & 0xF0) | (d & 0x0F); \
398 }
399#endif
400 LOOP(3, 0x1f, 0x18);
401 LOOP(2, 0x17, 0x10);
402 LOOP(1, 0x0f, 0x08);
403 LOOP(0, 0x07, 0x00);
404
405#undef LOOP
406
407 fb += SYSVID_WIDTH;
408 g += SPRITES_NBR_COLS;
409 }
410}
411
412#endif
413
414
415/*
416 * Draw a sprite
417 * align to tile column, determine plane automatically, and clip
418 *
419 * nbr: sprite number
420 * x, y: sprite position (pixels, map).
421 * fb: CHANGED
422 */
423#ifdef GFXPC
424void
425draw_sprite2(U8 number, U16 x, U16 y, bool front)
426{
427 U8 k, *f, c, r, dx;
428 U16 cmax, rmax;
429 U16 xm = 0, xp = 0;
430 S16 xmap, ymap;
431
432 /* align to tile column, prepare map coordinate and clip */
433 xmap = x & 0xFFF8;
434 ymap = y;
435 cmax = SPRITES_NBR_COLS * 8; /* width, 4 tile columns, 8 pixels each */
436 rmax = SPRITES_NBR_ROWS; /* height, 15 pixels */
437 dx = (x - xmap) * 2;
438 if (draw_clipms(&xmap, &ymap, &cmax, &rmax)) /* return if not visible */
439 return;
440
441 /* get back to screen */
442 draw_setfb(xmap - DRAW_XYMAP_SCRLEFT, ymap - DRAW_XYMAP_SCRTOP);
443 xmap >>= 3;
444 cmax >>= 3;
445
446 /* draw */
447 for (c = 0; c < cmax; c++) { /* for each tile column */
448 f = fb;
449 for (r = 0; r < rmax; r++) { /* for each pixel row */
450 /* check that tile is not hidden behind foreground */
451#ifdef ENABLE_CHEATS
452 if (front || game_cheat3 ||
453 !(map_eflg[map_map[(ymap + r) >> 3][xmap + c]] & MAP_EFLG_FGND)) {
454#else
455 if (front ||
456 !(map_eflg[map_map[(ymap + r) >> 3][xmap + c]] & MAP_EFLG_FGND)) {
457#endif
458 xp = xm = 0;
459 if (c > 0) {
460 xm |= sprites_data[number][c - 1][r].mask << (16 - dx);
461 xp |= sprites_data[number][c - 1][r].pict << (16 - dx);
462 }
463 else
464 xm |= 0xFFFF << (16 - dx);
465 if (c < cmax) {
466 xm |= sprites_data[number][c][r].mask >> dx;
467 xp |= sprites_data[number][c][r].pict >> dx;
468 }
469 else
470 xm |= 0xFFFF >> dx;
471 /*
472 * sprites / perform the transformation from CGA 2 bits
473 * per pixel to frame buffer 8 bits per pixels
474 */
475 for (k = 8; k--; xm >>= 2, xp >>= 2) {
476 f[k] = ((f[k] & (xm & 3)) | (xp & 3));
477#ifdef ENABLE_CHEATS
478 if (game_cheat3) f[k] |= 4;
479#endif
480 }
481 }
482 f += SYSVID_WIDTH;
483 }
484 fb += 8;
485 }
486}
487#endif
488
489
490/*
491 * Redraw the map behind a sprite
492 * align to tile column and row, and clip
493 *
494 * x, y: sprite position (pixels, map).
495 */
496void
497draw_spriteBackground(U16 x, U16 y)
498{
499 U8 r, c;
500 U16 rmax, cmax;
501 S16 xmap, ymap;
502 U16 xs, ys;
503
504 /* aligne to column and row, prepare map coordinate, and clip */
505 xmap = x & 0xFFF8;
506 ymap = y & 0xFFF8;
507 cmax = (x - xmap == 0 ? 0x20 : 0x28); /* width, 4 tl cols, 8 pix each */
508 rmax = (y & 0x04) ? 0x20 : 0x18; /* height, 3 or 4 tile rows */
509 if (draw_clipms(&xmap, &ymap, &cmax, &rmax)) /* don't draw if fully clipped */
510 return;
511
512 /* get back to screen */
513 xs = xmap - DRAW_XYMAP_SCRLEFT;
514 ys = ymap - DRAW_XYMAP_SCRTOP;
515 xmap >>= 3;
516 ymap >>= 3;
517 cmax >>= 3;
518 rmax >>= 3;
519
520 /* draw */
521 for (r = 0; r < rmax; r++) { /* for each row */
522#ifdef GFXPC
523 draw_setfb(xs, ys + r * 8);
524#endif
525#ifdef GFXST
526 draw_setfb(xs, 8 + ys + r * 8);
527#endif
528 for (c = 0; c < cmax; c++) { /* for each column */
529 draw_tile(map_map[ymap + r][xmap + c]);
530 }
531 }
532}
533
534
535/*
536 * Draw entire map screen background tiles onto frame buffer.
537 *
538 * ASM 0af5, 0a54
539 */
540void
541draw_map(void)
542{
543 U8 i, j;
544
545 draw_tilesBank = map_tilesBank;
546
547 for (i = 0; i < 0x18; i++) /* 0x18 rows */
548 {
549#ifdef GFXPC
550 draw_setfb(-DRAW_XYMAP_SCRLEFT, (i * 8));
551#endif
552#ifdef GFXST
553 draw_setfb(-DRAW_XYMAP_SCRLEFT, 8 + (i * 8));
554#endif
555 for (j = 0; j < 0x20; j++) /* 0x20 tiles per row */
556 {
557 draw_tile(map_map[i + 8][j]);
558 }
559 }
560}
561
562
563/*
564 * Draw status indicators
565 *
566 * ASM 0309
567 */
568void
569draw_drawStatus(void)
570{
571 S8 i;
572 U32 sv;
573 static U8 s[7] = {0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0xfe};
574
575 draw_tilesBank = 0;
576
577 for (i = 5, sv = game_score; i >= 0; i--) {
578 s[i] = 0x30 + (U8)(sv % 10);
579 sv /= 10;
580 }
581 draw_tllst = s;
582
583 draw_setfb(DRAW_STATUS_SCORE_X, DRAW_STATUS_Y);
584 draw_tilesList();
585
586 draw_setfb(DRAW_STATUS_BULLETS_X, DRAW_STATUS_Y);
587 for (i = 0; i < game_bullets; i++)
588 draw_tile(TILES_BULLET);
589
590 draw_setfb(DRAW_STATUS_BOMBS_X, DRAW_STATUS_Y);
591 for (i = 0; i < game_bombs; i++)
592 draw_tile(TILES_BOMB);
593
594 draw_setfb(DRAW_STATUS_LIVES_X, DRAW_STATUS_Y);
595 for (i = 0; i < game_lives; i++)
596 draw_tile(TILES_RICK);
597}
598
599
600/*
601 * Draw info indicators
602 */
603#ifdef ENABLE_CHEATS
604void
605draw_infos(void)
606{
607 draw_tilesBank = 0;
608
609#ifdef GFXPC
610 draw_filter = 0xffff;
611#endif
612
613 draw_setfb(0x00, DRAW_STATUS_Y);
614 draw_tile(game_cheat1 ? 'T' : '@');
615 draw_setfb(0x08, DRAW_STATUS_Y);
616 draw_tile(game_cheat2 ? 'N' : '@');
617 draw_setfb(0x10, DRAW_STATUS_Y);
618 draw_tile(game_cheat3 ? 'V' : '@');
619}
620#endif
621
622
623/*
624 * Clear status indicators
625 */
626void
627draw_clearStatus(void)
628{
629 U8 i;
630
631#ifdef GFXPC
632 draw_tilesBank = map_tilesBank;
633#endif
634#ifdef GFXST
635 draw_tilesBank = 0;
636#endif
637 draw_setfb(DRAW_STATUS_SCORE_X, DRAW_STATUS_Y);
638 for (i = 0; i < DRAW_STATUS_LIVES_X/8 + 6 - DRAW_STATUS_SCORE_X/8; i++) {
639#ifdef GFXPC
640 draw_tile(map_map[MAP_ROW_SCRTOP + (DRAW_STATUS_Y / 8)][i]);
641#endif
642#ifdef GFXST
643 draw_tile('@');
644#endif
645 }
646}
647
648/*
649 * Draw a picture
650 */
651#ifdef GFXST
652void
653draw_pic(const pic_t * picture)
654{
655 U8 *f;
656 U16 i, j, k, pp;
657 U32 v;
658
659 draw_setfb(picture->xPos, picture->yPos);
660 pp = 0;
661
662 for (i = 0; i < picture->height; i++) { /* rows */
663 f = fb;
664 for (j = 0; j < picture->width; j += 8) { /* cols */
665 v = picture->pixels[pp++];
666 for (k = 8; k--; v >>= 4)
667 f[k] = v & 0x0F;
668 f += 8;
669 }
670 fb += SYSVID_WIDTH;
671 }
672}
673#endif
674
675
676/*
677 * Draw a bitmap
678 */
679void
680draw_img(img_t *image)
681{
682 U8 *f;
683 U16 i, j, pp;
684
685 sysvid_setPalette(image->colors, image->ncolors);
686
687 draw_setfb(image->xPos, image->yPos);
688 pp = 0;
689
690 for (i = 0; i < image->height; i++) /* rows */
691 {
692 f = fb;
693 for (j = 0; j < image->width; j++) /* cols */
694 {
695 f[j] = image->pixels[pp++];
696 }
697 fb += SYSVID_WIDTH;
698 }
699}
700
701
702/* eof */
diff --git a/apps/plugins/xrick/draw.h b/apps/plugins/xrick/draw.h
new file mode 100644
index 0000000000..15520bd799
--- /dev/null
+++ b/apps/plugins/xrick/draw.h
@@ -0,0 +1,65 @@
1/*
2 * xrick/draw.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _DRAW_H
17#define _DRAW_H
18
19#include "xrick/rects.h"
20#include "xrick/data/img.h"
21#ifdef GFXST
22#include "xrick/data/pics.h"
23#endif
24
25#include <stddef.h> /* size_t */
26
27/* map coordinates of the screen */
28#define DRAW_XYMAP_SCRLEFT (-0x0020)
29#define DRAW_XYMAP_SCRTOP (0x0040)
30/* map coordinates of the top of the hidden bottom of the map */
31#define DRAW_XYMAP_HBTOP (0x0100)
32
33extern U8 *draw_tllst;
34#ifdef GFXPC
35extern U16 draw_filter;
36#endif
37extern U8 draw_tilesBank;
38
39extern rect_t draw_STATUSRECT;
40extern const rect_t draw_SCREENRECT; /* whole fb */
41
42extern size_t game_color_count;
43extern img_color_t *game_colors;
44
45extern void draw_setfb(U16, U16);
46extern bool draw_clipms(S16 *, S16 *, U16 *, U16 *);
47extern void draw_tilesList(void);
48extern void draw_tilesListImm(U8 *);
49extern U8 draw_tilesSubList(void);
50extern void draw_tile(register U8);
51extern void draw_sprite(U8, U16, U16);
52extern void draw_sprite2(U8, U16, U16, bool);
53extern void draw_spriteBackground(U16, U16);
54extern void draw_map(void);
55extern void draw_drawStatus(void);
56extern void draw_clearStatus(void);
57#ifdef GFXST
58extern void draw_pic(const pic_t *);
59#endif
60extern void draw_infos(void);
61extern void draw_img(img_t *);
62
63#endif /* ndef _DRAW_H */
64
65/* eof */
diff --git a/apps/plugins/xrick/e_bomb.c b/apps/plugins/xrick/e_bomb.c
new file mode 100644
index 0000000000..7b9f8cf309
--- /dev/null
+++ b/apps/plugins/xrick/e_bomb.c
@@ -0,0 +1,158 @@
1/*
2 * xrick/e_bomb.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_bomb.h"
17
18#include "xrick/game.h"
19#include "xrick/ents.h"
20#include "xrick/e_rick.h"
21#include "xrick/system/system.h"
22#ifdef ENABLE_SOUND
23#include "xrick/data/sounds.h"
24#endif
25
26/*
27 * public vars (for performance reasons)
28 */
29bool e_bomb_lethal;
30U8 e_bomb_xc;
31U16 e_bomb_yc;
32
33/*
34 * private vars
35 */
36U8 e_bomb_ticker;
37
38/*
39 * Bomb hit test
40 *
41 * ASM 11CD
42 * returns: true/hit, false/not
43 */
44bool e_bomb_hit(U8 e)
45{
46 if (ent_ents[e].x > (E_BOMB_ENT.x >= 0xE0 ? 0xFF : E_BOMB_ENT.x + 0x20))
47 return false;
48 if (ent_ents[e].x + ent_ents[e].w < (E_BOMB_ENT.x > 0x04 ? E_BOMB_ENT.x - 0x04 : 0))
49 return false;
50 if (ent_ents[e].y > (E_BOMB_ENT.y + 0x1D))
51 return false;
52 if (ent_ents[e].y + ent_ents[e].h < (E_BOMB_ENT.y > 0x0004 ? E_BOMB_ENT.y - 0x0004 : 0))
53 return false;
54 return true;
55}
56
57/*
58 * Initialize bomb
59 */
60void e_bomb_init(U16 x, U16 y)
61{
62 E_BOMB_ENT.n = 0x03;
63 E_BOMB_ENT.x = x;
64 E_BOMB_ENT.y = y;
65 e_bomb_ticker = E_BOMB_TICKER;
66 e_bomb_lethal = false;
67
68 /*
69 * Atari ST dynamite sprites are not centered the
70 * way IBM PC sprites were ... need to adjust things a little bit
71 */
72#ifdef GFXST
73 E_BOMB_ENT.x += 4;
74 E_BOMB_ENT.y += 5;
75#endif
76
77}
78
79
80/*
81 * Entity action
82 *
83 * ASM 18CA
84 */
85void
86e_bomb_action(U8 e/*unused*/)
87{
88 (void)e;
89
90 /* tick */
91 e_bomb_ticker--;
92
93 if (e_bomb_ticker == 0)
94 {
95 /*
96 * end: deactivate
97 */
98 E_BOMB_ENT.n = 0;
99 e_bomb_lethal = false;
100 }
101 else if (e_bomb_ticker >= 0x0A)
102 {
103 /*
104 * ticking
105 */
106#ifdef ENABLE_SOUND
107 if ((e_bomb_ticker & 0x03) == 0x02)
108 syssnd_play(soundBombshht, 1);
109#endif
110#ifdef GFXST
111 /* ST bomb sprites sequence is longer */
112 if (e_bomb_ticker < 40)
113 E_BOMB_ENT.sprite = 0x99 + 19 - (e_bomb_ticker >> 1);
114 else
115#endif
116 E_BOMB_ENT.sprite = (e_bomb_ticker & 0x01) ? 0x23 : 0x22;
117 }
118 else if (e_bomb_ticker == 0x09)
119 {
120 /*
121 * explode
122 */
123#ifdef ENABLE_SOUND
124 syssnd_play(soundExplode, 1);
125#endif
126#ifdef GFXPC
127 E_BOMB_ENT.sprite = 0x24 + 4 - (e_bomb_ticker >> 1);
128#endif
129#ifdef GFXST
130 /* See above: fixing alignment */
131 E_BOMB_ENT.x -= 4;
132 E_BOMB_ENT.y -= 5;
133 E_BOMB_ENT.sprite = 0xa8 + 4 - (e_bomb_ticker >> 1);
134#endif
135 e_bomb_xc = E_BOMB_ENT.x + 0x0C;
136 e_bomb_yc = E_BOMB_ENT.y + 0x000A;
137 e_bomb_lethal = true;
138 if (e_bomb_hit(E_RICK_NO))
139 e_rick_gozombie();
140 }
141 else
142 {
143 /*
144 * exploding
145 */
146#ifdef GFXPC
147 E_BOMB_ENT.sprite = 0x24 + 4 - (e_bomb_ticker >> 1);
148#endif
149#ifdef GFXST
150 E_BOMB_ENT.sprite = 0xa8 + 4 - (e_bomb_ticker >> 1);
151#endif
152 /* exploding, hence lethal */
153 if (e_bomb_hit(E_RICK_NO))
154 e_rick_gozombie();
155 }
156}
157
158/* eof */
diff --git a/apps/plugins/xrick/e_bomb.h b/apps/plugins/xrick/e_bomb.h
new file mode 100644
index 0000000000..93d66f7084
--- /dev/null
+++ b/apps/plugins/xrick/e_bomb.h
@@ -0,0 +1,36 @@
1/*
2 * xrick/e_bomb.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_BOMB_H
17#define _E_BOMB_H
18
19#include "xrick/system/basic_types.h"
20
21#define E_BOMB_NO 3
22#define E_BOMB_ENT ent_ents[E_BOMB_NO]
23#define E_BOMB_TICKER (0x2D)
24
25extern bool e_bomb_lethal;
26extern U8 e_bomb_ticker;
27extern U8 e_bomb_xc;
28extern U16 e_bomb_yc;
29
30extern bool e_bomb_hit(U8);
31extern void e_bomb_init(U16, U16);
32extern void e_bomb_action(U8);
33
34#endif /* ndef _E_BOMB_H */
35
36/* eof */
diff --git a/apps/plugins/xrick/e_bonus.c b/apps/plugins/xrick/e_bonus.c
new file mode 100644
index 0000000000..cc45bbfc99
--- /dev/null
+++ b/apps/plugins/xrick/e_bonus.c
@@ -0,0 +1,60 @@
1/*
2 * xrick/e_bonus.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_bonus.h"
17
18#include "xrick/game.h"
19#include "xrick/ents.h"
20
21#include "xrick/e_rick.h"
22#include "xrick/maps.h"
23
24
25/*
26 * Entity action
27 *
28 * ASM 242C
29 */
30void
31e_bonus_action(U8 e)
32{
33#define seq c1
34
35 if (ent_ents[e].seq == 0) {
36 if (e_rick_boxtest(e)) {
37 game_score += 500;
38#ifdef ENABLE_SOUND
39 syssnd_play(soundBonus, 1);
40#endif
41 map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT;
42 ent_ents[e].seq = 1;
43 ent_ents[e].sprite = 0xad;
44 ent_ents[e].front = true;
45 ent_ents[e].y -= 0x08;
46 }
47 }
48
49 else if (ent_ents[e].seq > 0 && ent_ents[e].seq < 10) {
50 ent_ents[e].seq++;
51 ent_ents[e].y -= 2;
52 }
53
54 else {
55 ent_ents[e].n = 0;
56 }
57}
58
59
60/* eof */
diff --git a/apps/plugins/xrick/e_bonus.h b/apps/plugins/xrick/e_bonus.h
new file mode 100644
index 0000000000..a2839e2a7a
--- /dev/null
+++ b/apps/plugins/xrick/e_bonus.h
@@ -0,0 +1,25 @@
1/*
2 * xrick/e_bonus.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_BONUS_H
17#define _E_BONUS_H
18
19#include "xrick/system/basic_types.h"
20
21extern void e_bonus_action(U8);
22
23#endif /* ndef _E_BONUS_H */
24
25/* eof */
diff --git a/apps/plugins/xrick/e_box.c b/apps/plugins/xrick/e_box.c
new file mode 100644
index 0000000000..25884b1a12
--- /dev/null
+++ b/apps/plugins/xrick/e_box.c
@@ -0,0 +1,109 @@
1/*
2 * xrick/e_box.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_box.h"
17
18#include "xrick/game.h"
19#include "xrick/ents.h"
20#include "xrick/e_bullet.h"
21#include "xrick/e_bomb.h"
22#include "xrick/e_rick.h"
23#include "xrick/maps.h"
24#include "xrick/util.h"
25
26/*
27 * FIXME this is because the same structure is used
28 * for all entities. Need to replace this w/ an inheritance
29 * solution.
30 */
31#define cnt c1
32
33/*
34 * Constants
35 */
36#define SEQ_INIT 0x0A
37
38/*
39 * Prototypes
40 */
41static void explode(U8);
42
43/*
44 * Entity action
45 *
46 * ASM 245A
47 */
48void
49e_box_action(U8 e)
50{
51 static U8 sp[] = {0x24, 0x25, 0x26, 0x27, 0x28}; /* explosion sprites sequence */
52
53 if (ent_ents[e].n & ENT_LETHAL) {
54 /*
55 * box is lethal i.e. exploding
56 * play sprites sequence then stop
57 */
58 ent_ents[e].sprite = sp[ent_ents[e].cnt >> 1];
59 if (--ent_ents[e].cnt == 0) {
60 ent_ents[e].n = 0;
61 map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT;
62 }
63 } else {
64 /*
65 * not lethal: check to see if triggered
66 */
67 if (e_rick_boxtest(e)) {
68 /* rick: collect bombs or bullets and stop */
69#ifdef ENABLE_SOUND
70 syssnd_play(soundBox, 1);
71#endif
72 if (ent_ents[e].n == 0x10)
73 game_bombs = GAME_BOMBS_INIT;
74 else /* 0x11 */
75 game_bullets = GAME_BULLETS_INIT;
76 ent_ents[e].n = 0;
77 map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT;
78 }
79 else if (e_rick_state_test(E_RICK_STSTOP) &&
80 u_fboxtest(e, e_rick_stop_x, e_rick_stop_y)) {
81 /* rick's stick: explode */
82 explode(e);
83 }
84 else if (E_BULLET_ENT.n && u_fboxtest(e, e_bullet_xc, e_bullet_yc)) {
85 /* bullet: explode (and stop bullet) */
86 E_BULLET_ENT.n = 0;
87 explode(e);
88 }
89 else if (e_bomb_lethal && e_bomb_hit(e)) {
90 /* bomb: explode */
91 explode(e);
92 }
93 }
94}
95
96
97/*
98 * Explode when
99 */
100static void explode(U8 e)
101{
102 ent_ents[e].cnt = SEQ_INIT;
103 ent_ents[e].n |= ENT_LETHAL;
104#ifdef ENABLE_SOUND
105 syssnd_play(soundExplode, 1);
106#endif
107}
108
109/* eof */
diff --git a/apps/plugins/xrick/e_box.h b/apps/plugins/xrick/e_box.h
new file mode 100644
index 0000000000..1271449bf5
--- /dev/null
+++ b/apps/plugins/xrick/e_box.h
@@ -0,0 +1,25 @@
1/*
2 * xrick/e_box.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_BOX_H
17#define _E_BOX_H
18
19#include "xrick/system/basic_types.h"
20
21extern void e_box_action(U8);
22
23#endif /* ndef _E_BOX_H */
24
25/* eof */
diff --git a/apps/plugins/xrick/e_bullet.c b/apps/plugins/xrick/e_bullet.c
new file mode 100644
index 0000000000..86542256e8
--- /dev/null
+++ b/apps/plugins/xrick/e_bullet.c
@@ -0,0 +1,84 @@
1/*
2 * xrick/e_bullet.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_bullet.h"
17
18#include "xrick/system/system.h"
19#include "xrick/game.h"
20#include "xrick/ents.h"
21#include "xrick/maps.h"
22
23/*
24 * public vars (for performance reasons)
25 */
26S8 e_bullet_offsx;
27S16 e_bullet_xc, e_bullet_yc;
28
29/*
30 * Initialize bullet
31 */
32void
33e_bullet_init(U16 x, U16 y)
34{
35 E_BULLET_ENT.n = 0x02;
36 E_BULLET_ENT.x = x;
37 E_BULLET_ENT.y = y + 0x0006;
38 if (game_dir == LEFT) {
39 e_bullet_offsx = -0x08;
40 E_BULLET_ENT.sprite = 0x21;
41 }
42 else {
43 e_bullet_offsx = 0x08;
44 E_BULLET_ENT.sprite = 0x20;
45 }
46#ifdef ENABLE_SOUND
47 syssnd_play(soundBullet, 1);
48#endif
49}
50
51
52/*
53 * Entity action
54 *
55 * ASM 1883, 0F97
56 */
57void
58e_bullet_action(U8 e/*unused*/)
59{
60 (void)e;
61
62 /* move bullet */
63 E_BULLET_ENT.x += e_bullet_offsx;
64
65 if (E_BULLET_ENT.x <= -0x10 || E_BULLET_ENT.x > 0xe8)
66 {
67 /* out: deactivate */
68 E_BULLET_ENT.n = 0;
69 }
70 else
71 {
72 /* update bullet center coordinates */
73 e_bullet_xc = E_BULLET_ENT.x + 0x0c;
74 e_bullet_yc = E_BULLET_ENT.y + 0x05;
75 if (map_eflg[map_map[e_bullet_yc >> 3][e_bullet_xc >> 3]] & MAP_EFLG_SOLID)
76 {
77 /* hit something: deactivate */
78 E_BULLET_ENT.n = 0;
79 }
80 }
81}
82
83
84/* eof */
diff --git a/apps/plugins/xrick/e_bullet.h b/apps/plugins/xrick/e_bullet.h
new file mode 100644
index 0000000000..5b8c78b709
--- /dev/null
+++ b/apps/plugins/xrick/e_bullet.h
@@ -0,0 +1,32 @@
1/*
2 * xrick/e_bullet.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_BULLET_H
17#define _E_BULLET_H
18
19#include "xrick/system/basic_types.h"
20
21#define E_BULLET_NO 2
22#define E_BULLET_ENT ent_ents[E_BULLET_NO]
23
24extern S8 e_bullet_offsx;
25extern S16 e_bullet_xc, e_bullet_yc;
26
27extern void e_bullet_init(U16, U16);
28extern void e_bullet_action(U8);
29
30#endif /* ndef _E_BULLET_H */
31
32/* eof */
diff --git a/apps/plugins/xrick/e_rick.c b/apps/plugins/xrick/e_rick.c
new file mode 100644
index 0000000000..548a4f9681
--- /dev/null
+++ b/apps/plugins/xrick/e_rick.c
@@ -0,0 +1,606 @@
1/*
2 * xrick/e_rick.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_rick.h"
17
18#include "xrick/system/system.h"
19#include "xrick/config.h"
20#include "xrick/game.h"
21#include "xrick/ents.h"
22#include "xrick/e_bullet.h"
23#include "xrick/e_bomb.h"
24#include "xrick/control.h"
25#include "xrick/maps.h"
26#include "xrick/util.h"
27
28/*
29 * public vars
30 */
31S16 e_rick_stop_x = 0;
32S16 e_rick_stop_y = 0;
33unsigned e_rick_state = 0;
34
35/*
36* public functions
37*/
38extern inline void e_rick_state_set(e_rick_state_t s);
39extern inline void e_rick_state_clear(e_rick_state_t s);
40extern inline bool e_rick_state_test(e_rick_state_t s);
41
42
43/*
44 * local vars
45 */
46static U8 scrawl;
47
48static bool trigger = false;
49
50static S8 offsx;
51static U8 ylow;
52static S16 offsy;
53
54static U8 seq;
55
56static U8 save_crawl, save_direction;
57static U16 save_x, save_y;
58
59
60/*
61 * Box test
62 *
63 * ASM 113E (based on)
64 *
65 * e: entity to test against (corresponds to SI in asm code -- here DI
66 * is assumed to point to rick).
67 * ret: true/intersect, false/not.
68 */
69bool
70e_rick_boxtest(U8 e)
71{
72 /*
73 * rick: x+0x05 to x+0x11, y+[0x08 if rick's crawling] to y+0x14
74 * entity: x to x+w, y to y+h
75 */
76
77 if (E_RICK_ENT.x + 0x11 < ent_ents[e].x ||
78 E_RICK_ENT.x + 0x05 > ent_ents[e].x + ent_ents[e].w ||
79 E_RICK_ENT.y + 0x14 < ent_ents[e].y ||
80 E_RICK_ENT.y + (e_rick_state_test(E_RICK_STCRAWL) ? 0x08 : 0x00) > ent_ents[e].y + ent_ents[e].h - 1)
81 return false;
82 else
83 return true;
84}
85
86
87
88
89/*
90 * Go zombie
91 *
92 * ASM 1851
93 */
94void
95e_rick_gozombie(void)
96{
97#ifdef ENABLE_CHEATS
98 if (game_cheat2) return;
99#endif
100
101 /* already zombie? */
102 if (e_rick_state_test(E_RICK_STZOMBIE)) return;
103
104#ifdef ENABLE_SOUND
105 syssnd_play(soundDie, 1);
106#endif
107
108 e_rick_state_set(E_RICK_STZOMBIE);
109 offsy = -0x0300;
110 offsx = (E_RICK_ENT.x > 0x80 ? -3 : +3);
111 ylow = 0;
112 E_RICK_ENT.front = true;
113}
114
115
116/*
117 * Action sub-function for e_rick when zombie
118 *
119 * ASM 17DC
120 */
121static void
122e_rick_z_action(void)
123{
124 U32 i;
125
126 /* sprite */
127 E_RICK_ENT.sprite = (E_RICK_ENT.x & 0x04) ? 0x1A : 0x19;
128
129 /* x */
130 E_RICK_ENT.x += offsx;
131
132 /* y */
133 i = (E_RICK_ENT.y << 8) + offsy + ylow;
134 E_RICK_ENT.y = i >> 8;
135 offsy += 0x80;
136 ylow = i;
137
138 /* dead when out of screen */
139 if (E_RICK_ENT.y < 0 || E_RICK_ENT.y > 0x0140)
140 {
141 e_rick_state_set(E_RICK_STDEAD);
142 }
143}
144
145
146/*
147 * Action sub-function for e_rick.
148 *
149 * ASM 13BE
150 */
151void
152e_rick_action2(void)
153{
154 U8 env0, env1;
155 S16 x, y;
156 U32 i;
157
158 e_rick_state_clear(E_RICK_STSTOP | E_RICK_STSHOOT);
159
160 /* if zombie, run dedicated function and return */
161 if (e_rick_state_test(E_RICK_STZOMBIE))
162 {
163 e_rick_z_action();
164 return;
165 }
166
167 /* climbing? */
168 if (e_rick_state_test(E_RICK_STCLIMB))
169 {
170 goto climbing;
171 }
172 /*
173 * NOT CLIMBING
174 */
175 e_rick_state_clear(E_RICK_STJUMP);
176 /* calc y */
177 i = (E_RICK_ENT.y << 8) + offsy + ylow;
178 y = i >> 8;
179 /* test environment */
180 u_envtest(E_RICK_ENT.x, y, e_rick_state_test(E_RICK_STCRAWL), &env0, &env1);
181 /* stand up, if possible */
182 if (e_rick_state_test(E_RICK_STCRAWL) && !env0)
183 {
184 e_rick_state_clear(E_RICK_STCRAWL);
185 }
186 /* can move vertically? */
187 if (env1 & (offsy < 0 ?
188 MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD :
189 MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))
190 goto vert_not;
191
192 /*
193 * VERTICAL MOVE
194 */
195 e_rick_state_set(E_RICK_STJUMP);
196 /* killed? */
197 if (env1 & MAP_EFLG_LETHAL) {
198 e_rick_gozombie();
199 return;
200 }
201 /* save */
202 E_RICK_ENT.y = y;
203 ylow = i;
204 /* climb? */
205 if ((env1 & MAP_EFLG_CLIMB) && (control_test(Control_UP | Control_DOWN)))
206 {
207 offsy = 0x0100;
208 e_rick_state_set(E_RICK_STCLIMB);
209 return;
210 }
211 /* fall */
212 offsy += 0x0080;
213 if (offsy > 0x0800) {
214 offsy = 0x0800;
215 ylow = 0;
216 }
217
218 /*
219 * HORIZONTAL MOVE
220 */
221 horiz:
222 /* should move? */
223 if (!(control_test(Control_LEFT | Control_RIGHT))) {
224 seq = 2; /* no: reset seq and return */
225 return;
226 }
227 if (control_test(Control_LEFT)) { /* move left */
228 x = E_RICK_ENT.x - 2;
229 game_dir = LEFT;
230 if (x < 0) { /* prev submap */
231 game_chsm = true;
232 E_RICK_ENT.x = 0xe2;
233 return;
234 }
235 } else { /* move right */
236 x = E_RICK_ENT.x + 2;
237 game_dir = RIGHT;
238 if (x >= 0xe8) { /* next submap */
239 game_chsm = true;
240 E_RICK_ENT.x = 0x04;
241 return;
242 }
243 }
244
245 /* still within this map: test environment */
246 u_envtest(x, E_RICK_ENT.y, e_rick_state_test(E_RICK_STCRAWL), &env0, &env1);
247
248 /* save x-position if it is possible to move */
249 if (!(env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))) {
250 E_RICK_ENT.x = x;
251 if (env1 & MAP_EFLG_LETHAL) e_rick_gozombie();
252 }
253
254 /* end */
255 return;
256
257 /*
258 * NO VERTICAL MOVE
259 */
260 vert_not:
261 if (offsy < 0) {
262 /* not climbing + trying to go _up_ not possible -> hit the roof */
263 e_rick_state_set(E_RICK_STJUMP); /* fall back to the ground */
264 E_RICK_ENT.y &= 0xF8;
265 offsy = 0;
266 ylow = 0;
267 goto horiz;
268 }
269 /* else: not climbing + trying to go _down_ not possible -> standing */
270 /* align to ground */
271 E_RICK_ENT.y &= 0xF8;
272 E_RICK_ENT.y |= 0x03;
273 ylow = 0;
274
275 /* standing on a super pad? */
276 if ((env1 & MAP_EFLG_SPAD) && offsy >= 0X0200) {
277 offsy = (control_test(Control_UP)) ? 0xf800 : 0x00fe - offsy;
278#ifdef ENABLE_SOUND
279 syssnd_play(soundPad, 1);
280#endif
281 goto horiz;
282 }
283
284 offsy = 0x0100; /* reset*/
285
286 /* standing. firing ? */
287 if (scrawl || !(control_test(Control_FIRE)))
288 goto firing_not;
289
290 /*
291 * FIRING
292 */
293 if (control_test(Control_LEFT | Control_RIGHT)) { /* stop */
294 if (control_test(Control_RIGHT))
295 {
296 game_dir = RIGHT;
297 e_rick_stop_x = E_RICK_ENT.x + 0x17;
298 } else {
299 game_dir = LEFT;
300 e_rick_stop_x = E_RICK_ENT.x;
301 }
302 e_rick_stop_y = E_RICK_ENT.y + 0x000E;
303 e_rick_state_set(E_RICK_STSTOP);
304 return;
305 }
306
307 if (control_test(Control_UP)) { /* bullet */
308 e_rick_state_set(E_RICK_STSHOOT);
309 /* not an automatic gun: shoot once only */
310 if (trigger)
311 return;
312 else
313 trigger = true;
314 /* already a bullet in the air ... that's enough */
315 if (E_BULLET_ENT.n)
316 return;
317 /* else use a bullet, if any available */
318 if (!game_bullets)
319 return;
320#ifdef ENABLE_CHEATS
321 if (!game_cheat1)
322#endif
323 {
324 game_bullets--;
325 }
326
327 /* initialize bullet */
328 e_bullet_init(E_RICK_ENT.x, E_RICK_ENT.y);
329 return;
330 }
331
332 trigger = false; /* not shooting means trigger is released */
333 seq = 0; /* reset */
334
335 if (control_test(Control_DOWN)) { /* bomb */
336 /* already a bomb ticking ... that's enough */
337 if (E_BOMB_ENT.n)
338 return;
339 /* else use a bomb, if any available */
340 if (!game_bombs)
341 return;
342#ifdef ENABLE_CHEATS
343 if (!game_cheat1)
344#endif
345 {
346 game_bombs--;
347 }
348
349 /* initialize bomb */
350 e_bomb_init(E_RICK_ENT.x, E_RICK_ENT.y);
351 return;
352 }
353
354 return;
355
356 /*
357 * NOT FIRING
358 */
359 firing_not:
360 if (control_test(Control_UP)) { /* jump or climb */
361 if (env1 & MAP_EFLG_CLIMB) { /* climb */
362 e_rick_state_set(E_RICK_STCLIMB);
363 return;
364 }
365 offsy = -0x0580; /* jump */
366 ylow = 0;
367#ifdef ENABLE_SOUND
368 syssnd_play(soundJump, 1);
369#endif
370 goto horiz;
371 }
372 if (control_test(Control_DOWN)) { /* crawl or climb */
373 if ((env1 & MAP_EFLG_VERT) && /* can go down */
374 !(control_test(Control_LEFT | Control_RIGHT)) && /* + not moving horizontaly */
375 (E_RICK_ENT.x & 0x1f) < 0x0a) { /* + aligned -> climb */
376 E_RICK_ENT.x &= 0xf0;
377 E_RICK_ENT.x |= 0x04;
378 e_rick_state_set(E_RICK_STCLIMB);
379 }
380 else { /* crawl */
381 e_rick_state_set(E_RICK_STCRAWL);
382 goto horiz;
383 }
384
385 }
386 goto horiz;
387
388 /*
389 * CLIMBING
390 */
391 climbing:
392 /* should move? */
393 if (!(control_test(Control_UP | Control_DOWN | Control_LEFT | Control_RIGHT))) {
394 seq = 0; /* no: reset seq and return */
395 return;
396 }
397
398 if (control_test(Control_UP | Control_DOWN)) {
399 /* up-down: calc new y and test environment */
400 y = E_RICK_ENT.y + ((control_test(Control_UP)) ? -0x02 : 0x02);
401 u_envtest(E_RICK_ENT.x, y, e_rick_state_test(E_RICK_STCRAWL), &env0, &env1);
402 if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP) &&
403 !(control_test(Control_UP))) {
404 /* FIXME what? */
405 e_rick_state_clear(E_RICK_STCLIMB);
406 return;
407 }
408 if (!(env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP)) ||
409 (env1 & MAP_EFLG_WAYUP)) {
410 /* ok to move, save */
411 E_RICK_ENT.y = y;
412 if (env1 & MAP_EFLG_LETHAL) {
413 e_rick_gozombie();
414 return;
415 }
416 if (!(env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB))) {
417 /* reached end of climb zone */
418 offsy = (control_test(Control_UP)) ? -0x0300 : 0x0100;
419#ifdef ENABLE_SOUND
420 if (control_test(Control_UP))
421 syssnd_play(soundJump, 1);
422#endif
423 e_rick_state_clear(E_RICK_STCLIMB);
424 return;
425 }
426 }
427 }
428 if (control_test(Control_LEFT | Control_RIGHT)) {
429 /* left-right: calc new x and test environment */
430 if (control_test(Control_LEFT)) {
431 x = E_RICK_ENT.x - 0x02;
432 if (x < 0) { /* (i.e. negative) prev submap */
433 game_chsm = true;
434 /*6dbd = 0x00;*/
435 E_RICK_ENT.x = 0xe2;
436 return;
437 }
438 }
439 else {
440 x = E_RICK_ENT.x + 0x02;
441 if (x >= 0xe8) { /* next submap */
442 game_chsm = true;
443 /*6dbd = 0x01;*/
444 E_RICK_ENT.x = 0x04;
445 return;
446 }
447 }
448 u_envtest(x, E_RICK_ENT.y, e_rick_state_test(E_RICK_STCRAWL), &env0, &env1);
449 if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD)) return;
450 E_RICK_ENT.x = x;
451 if (env1 & MAP_EFLG_LETHAL) {
452 e_rick_gozombie();
453 return;
454 }
455
456 if (env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB)) return;
457 e_rick_state_clear(E_RICK_STCLIMB);
458 if (control_test(Control_UP))
459 offsy = -0x0300;
460 }
461}
462
463
464/*
465 * Action function for e_rick
466 *
467 * ASM 12CA
468 */
469void e_rick_action(U8 e/*unused*/)
470{
471 static U8 stopped = false; /* is this the most elegant way? */
472
473 (void)e;
474
475 e_rick_action2();
476
477 scrawl = e_rick_state_test(E_RICK_STCRAWL);
478
479 if (e_rick_state_test(E_RICK_STZOMBIE))
480 {
481 return;
482 }
483 /*
484 * set sprite
485 */
486
487 if (e_rick_state_test(E_RICK_STSTOP))
488 {
489 E_RICK_ENT.sprite = (game_dir ? 0x17 : 0x0B);
490#ifdef ENABLE_SOUND
491 if (!stopped)
492 {
493 syssnd_play(soundStick, 1);
494 stopped = true;
495 }
496#endif
497 return;
498 }
499
500 stopped = false;
501
502 if (e_rick_state_test(E_RICK_STSHOOT))
503 {
504 E_RICK_ENT.sprite = (game_dir ? 0x16 : 0x0A);
505 return;
506 }
507
508 if (e_rick_state_test(E_RICK_STCLIMB))
509 {
510 E_RICK_ENT.sprite = (((E_RICK_ENT.x ^ E_RICK_ENT.y) & 0x04) ? 0x18 : 0x0c);
511#ifdef ENABLE_SOUND
512 seq = (seq + 1) & 0x03;
513 if (seq == 0) syssnd_play(soundWalk, 1);
514#endif
515 return;
516 }
517
518 if (e_rick_state_test(E_RICK_STCRAWL))
519 {
520 E_RICK_ENT.sprite = (game_dir ? 0x13 : 0x07);
521 if (E_RICK_ENT.x & 0x04) E_RICK_ENT.sprite++;
522#ifdef ENABLE_SOUND
523 seq = (seq + 1) & 0x03;
524 if (seq == 0) syssnd_play(soundCrawl, 1);
525#endif
526 return;
527 }
528
529 if (e_rick_state_test(E_RICK_STJUMP))
530 {
531 E_RICK_ENT.sprite = (game_dir ? 0x15 : 0x06);
532 return;
533 }
534
535 seq++;
536
537 if (seq >= 0x14)
538 {
539#ifdef ENABLE_SOUND
540 syssnd_play(soundWalk, 1);
541#endif
542 seq = 0x04;
543 }
544#ifdef ENABLE_SOUND
545 else
546 {
547 if (seq == 0x0C)
548 {
549 syssnd_play(soundWalk, 1);
550 }
551 }
552#endif
553
554 E_RICK_ENT.sprite = (seq >> 2) + 1 + (game_dir ? 0x0c : 0x00);
555}
556
557
558/*
559 * Save status
560 *
561 * ASM part of 0x0BBB
562 */
563void e_rick_save(void)
564{
565 save_x = E_RICK_ENT.x;
566 save_y = E_RICK_ENT.y;
567 save_crawl = e_rick_state_test(E_RICK_STCRAWL);
568 save_direction = game_dir;
569 /* FIXME
570 * save_C0 = E_RICK_ENT.b0C;
571 * plus some 6DBC stuff?
572 */
573}
574
575
576/*
577 * Restore status
578 *
579 * ASM part of 0x0BDC
580 */
581void e_rick_restore(void)
582{
583 E_RICK_ENT.x = save_x;
584 E_RICK_ENT.y = save_y;
585 if (save_crawl)
586 {
587 e_rick_state_set(E_RICK_STCRAWL);
588 }
589 else
590 {
591 e_rick_state_clear(E_RICK_STCRAWL);
592 }
593 game_dir = save_direction;
594
595 E_RICK_ENT.front = false;
596 e_rick_state_clear(E_RICK_STCLIMB); /* should we clear other states? */
597 /* FIXME
598 * E_RICK_ENT.b0C = save_C0;
599 * plus some 6DBC stuff?
600 */
601}
602
603
604
605
606/* eof */
diff --git a/apps/plugins/xrick/e_rick.h b/apps/plugins/xrick/e_rick.h
new file mode 100644
index 0000000000..57b45366d7
--- /dev/null
+++ b/apps/plugins/xrick/e_rick.h
@@ -0,0 +1,50 @@
1/*
2 * xrick/e_rick.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_RICK_H
17#define _E_RICK_H
18
19#include "xrick/system/basic_types.h"
20
21#define E_RICK_NO 1
22#define E_RICK_ENT ent_ents[E_RICK_NO]
23
24typedef enum
25{
26 E_RICK_STSTOP = (1 << 0),
27 E_RICK_STSHOOT = (1 << 1),
28 E_RICK_STCLIMB = (1 << 2),
29 E_RICK_STJUMP = (1 << 3),
30 E_RICK_STZOMBIE = (1 << 4),
31 E_RICK_STDEAD = (1 << 5),
32 E_RICK_STCRAWL = (1 << 6),
33} e_rick_state_t;
34
35extern unsigned e_rick_state;
36inline void e_rick_state_set(e_rick_state_t s) { e_rick_state |= s; }
37inline void e_rick_state_clear(e_rick_state_t s) { e_rick_state &= ~s; }
38inline bool e_rick_state_test(e_rick_state_t s) { return e_rick_state & s; }
39
40extern S16 e_rick_stop_x, e_rick_stop_y;
41
42extern void e_rick_save(void);
43extern void e_rick_restore(void);
44extern void e_rick_action(U8);
45extern void e_rick_gozombie(void);
46extern bool e_rick_boxtest(U8);
47
48#endif /* ndef _E_RICK_H */
49
50/* eof */
diff --git a/apps/plugins/xrick/e_sbonus.c b/apps/plugins/xrick/e_sbonus.c
new file mode 100644
index 0000000000..1630d419aa
--- /dev/null
+++ b/apps/plugins/xrick/e_sbonus.c
@@ -0,0 +1,88 @@
1/*
2 * xrick/e_sbonus.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_sbonus.h"
17
18#include "xrick/game.h"
19#include "xrick/ents.h"
20#include "xrick/util.h"
21#include "xrick/maps.h"
22#include "xrick/e_rick.h"
23
24
25/*
26 * public vars
27 */
28bool e_sbonus_counting = false;
29U8 e_sbonus_counter = 0;
30U16 e_sbonus_bonus = 0;
31
32
33/*
34 * Entity action / start counting
35 *
36 * ASM 2182
37 */
38void
39e_sbonus_start(U8 e)
40{
41 ent_ents[e].sprite = 0; /* invisible */
42 if (u_trigbox(e, ENT_XRICK.x + 0x0C, ENT_XRICK.y + 0x0A)) {
43 /* rick is within trigger box */
44 ent_ents[e].n = 0;
45 e_sbonus_counting = true; /* 6DD5 */
46 e_sbonus_counter = 0x1e; /* 6DDB */
47 e_sbonus_bonus = 2000; /* 291A-291D */
48#ifdef ENABLE_SOUND
49 syssnd_play(soundSbonus1, 1);
50#endif
51 }
52}
53
54
55/*
56 * Entity action / stop counting
57 *
58 * ASM 2143
59 */
60void
61e_sbonus_stop(U8 e)
62{
63 ent_ents[e].sprite = 0; /* invisible */
64
65 if (!e_sbonus_counting)
66 return;
67
68 if (u_trigbox(e, ENT_XRICK.x + 0x0C, ENT_XRICK.y + 0x0A)) {
69 /* rick is within trigger box */
70 e_sbonus_counting = false; /* stop counting */
71 ent_ents[e].n = 0; /* deactivate entity */
72 game_score += e_sbonus_bonus; /* add bonus to score */
73#ifdef ENABLE_SOUND
74 syssnd_play(soundSbonus2, 1);
75#endif
76 /* make sure the entity won't be activated again */
77 map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT;
78 }
79 else {
80 /* keep counting */
81 if (--e_sbonus_counter == 0) {
82 e_sbonus_counter = 0x1e;
83 if (e_sbonus_bonus) e_sbonus_bonus--;
84 }
85 }
86}
87
88/* eof */
diff --git a/apps/plugins/xrick/e_sbonus.h b/apps/plugins/xrick/e_sbonus.h
new file mode 100644
index 0000000000..dbb29c9c99
--- /dev/null
+++ b/apps/plugins/xrick/e_sbonus.h
@@ -0,0 +1,30 @@
1/*
2 * xrick/e_sbonus.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_SBONUS_H
17#define _E_SBONUS_H
18
19#include "xrick/system/basic_types.h"
20
21extern bool e_sbonus_counting;
22extern U8 e_sbonus_counter;
23extern U16 e_sbonus_bonus;
24
25extern void e_sbonus_start(U8);
26extern void e_sbonus_stop(U8);
27
28#endif /* ndef _E_SBONUS_H */
29
30/* eof */
diff --git a/apps/plugins/xrick/e_them.c b/apps/plugins/xrick/e_them.c
new file mode 100644
index 0000000000..465325b652
--- /dev/null
+++ b/apps/plugins/xrick/e_them.c
@@ -0,0 +1,738 @@
1/*
2 * xrick/e_them.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/e_them.h"
17
18#include "xrick/game.h"
19#include "xrick/ents.h"
20#include "xrick/e_rick.h"
21#include "xrick/e_bomb.h"
22#include "xrick/e_bullet.h"
23#include "xrick/maps.h"
24#include "xrick/util.h"
25
26#define TYPE_1A (0x00)
27#define TYPE_1B (0xff)
28
29/*
30 * public vars
31 */
32U32 e_them_rndseed = 0;
33
34/*
35 * local vars
36 */
37static U16 e_them_rndnbr = 0;
38
39/*
40 * Check if entity boxtests with a lethal e_them i.e. something lethal
41 * in slot 0 and 4 to 8.
42 *
43 * ASM 122E
44 *
45 * e: entity slot number.
46 * ret: true/boxtests, false/not
47 */
48static bool
49u_themtest(U8 e)
50{
51 U8 i;
52
53 if ((ent_ents[0].n & ENT_LETHAL) && u_boxtest(e, 0))
54 return true;
55
56 for (i = 4; i < 9; i++)
57 if ((ent_ents[i].n & ENT_LETHAL) && u_boxtest(e, i))
58 return true;
59
60 return false;
61}
62
63
64/*
65 * Go zombie
66 *
67 * ASM 237B
68 */
69void
70e_them_gozombie(U8 e)
71{
72#define offsx c1
73 ent_ents[e].n = 0x47; /* zombie entity */
74 ent_ents[e].front = true;
75 ent_ents[e].offsy = -0x0400;
76#ifdef ENABLE_SOUND
77 syssnd_play(soundDie, 1);
78#endif
79 game_score += 50;
80 if (ent_ents[e].flags & ENT_FLG_ONCE) {
81 /* make sure entity won't be activated again */
82 map_marks[ent_ents[e].mark].ent |= MAP_MARK_NACT;
83 }
84 ent_ents[e].offsx = (ent_ents[e].x >= 0x80 ? -0x02 : 0x02);
85#undef offsx
86}
87
88
89/*
90 * Action sub-function for e_them _t1a and _t1b
91 *
92 * Those two types move horizontally, and fall if they have to.
93 * Type 1a moves horizontally over a given distance and then
94 * u-turns and repeats; type 1b is more subtle as it does u-turns
95 * in order to move horizontally towards rick.
96 *
97 * ASM 2242
98 */
99void
100e_them_t1_action2(U8 e, U8 type)
101{
102#define offsx c1
103#define step_count c2
104 U32 i;
105 S16 x, y;
106 U8 env0, env1;
107
108 /* by default, try vertical move. calculate new y */
109 i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow;
110 y = i >> 8;
111
112 /* deactivate if outside vertical boundaries */
113 /* no need to test zero since e_them _t1a/b don't go up */
114 /* FIXME what if they got scrolled out ? */
115 if (y > 0x140) {
116 ent_ents[e].n = 0;
117 return;
118 }
119
120 /* test environment */
121 u_envtest(ent_ents[e].x, y, false, &env0, &env1);
122
123 if (!(env1 & (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))) {
124 /* vertical move possible: falling */
125 if (env1 & MAP_EFLG_LETHAL) {
126 /* lethal entities kill e_them */
127 e_them_gozombie(e);
128 return;
129 }
130 /* save, cleanup and return */
131 ent_ents[e].y = y;
132 ent_ents[e].ylow = i;
133 ent_ents[e].offsy += 0x0080;
134 if (ent_ents[e].offsy > 0x0800)
135 ent_ents[e].offsy = 0x0800;
136 return;
137 }
138
139 /* vertical move not possible. calculate new sprite */
140 ent_ents[e].sprite = ent_ents[e].sprbase
141 + ent_sprseq[(ent_ents[e].x & 0x1c) >> 3]
142 + (ent_ents[e].offsx < 0 ? 0x03 : 0x00);
143
144 /* reset offsy */
145 ent_ents[e].offsy = 0x0080;
146
147 /* align to ground */
148 ent_ents[e].y &= 0xfff8;
149 ent_ents[e].y |= 0x0003;
150
151 /* latency: if not zero then decrease and return */
152 if (ent_ents[e].latency > 0) {
153 ent_ents[e].latency--;
154 return;
155 }
156
157 /* horizontal move. calculate new x */
158 if (ent_ents[e].offsx == 0) /* not supposed to move -> don't */
159 return;
160
161 x = ent_ents[e].x + ent_ents[e].offsx;
162 if (ent_ents[e].x < 0 || ent_ents[e].x > 0xe8) {
163 /* U-turn and return if reaching horizontal boundaries */
164 ent_ents[e].step_count = 0;
165 ent_ents[e].offsx = -ent_ents[e].offsx;
166 return;
167 }
168
169 /* test environment */
170 u_envtest(x, ent_ents[e].y, false, &env0, &env1);
171
172 if (env1 & (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP)) {
173 /* horizontal move not possible: u-turn and return */
174 ent_ents[e].step_count = 0;
175 ent_ents[e].offsx = -ent_ents[e].offsx;
176 return;
177 }
178
179 /* horizontal move possible */
180 if (env1 & MAP_EFLG_LETHAL) {
181 /* lethal entities kill e_them */
182 e_them_gozombie(e);
183 return;
184 }
185
186 /* save */
187 ent_ents[e].x = x;
188
189 /* depending on type, */
190 if (type == TYPE_1B) {
191 /* set direction to move horizontally towards rick */
192 if ((ent_ents[e].x & 0x1e) != 0x10) /* prevents too frequent u-turns */
193 return;
194 ent_ents[e].offsx = (ent_ents[e].x < E_RICK_ENT.x) ? 0x02 : -0x02;
195 return;
196 }
197 else {
198 /* set direction according to step counter */
199 ent_ents[e].step_count++;
200 /* FIXME why trig_x (b16) ?? */
201 if ((ent_ents[e].trig_x >> 1) > ent_ents[e].step_count)
202 return;
203 }
204
205 /* type is 1A and step counter reached its limit: u-turn */
206 ent_ents[e].step_count = 0;
207 ent_ents[e].offsx = -ent_ents[e].offsx;
208#undef offsx
209#undef step_count
210}
211
212
213/*
214 * ASM 21CF
215 */
216void
217e_them_t1_action(U8 e, U8 type)
218{
219 e_them_t1_action2(e, type);
220
221 /* lethal entities kill them */
222 if (u_themtest(e)) {
223 e_them_gozombie(e);
224 return;
225 }
226
227 /* bullet kills them */
228 if (E_BULLET_ENT.n &&
229 u_fboxtest(e, E_BULLET_ENT.x + (e_bullet_offsx < 0 ? 0 : 0x18),
230 E_BULLET_ENT.y)) {
231 E_BULLET_ENT.n = 0;
232 e_them_gozombie(e);
233 return;
234 }
235
236 /* bomb kills them */
237 if (e_bomb_lethal && e_bomb_hit(e)) {
238 e_them_gozombie(e);
239 return;
240 }
241
242 /* rick stops them */
243 if (e_rick_state_test(E_RICK_STSTOP) &&
244 u_fboxtest(e, e_rick_stop_x, e_rick_stop_y))
245 ent_ents[e].latency = 0x14;
246
247 /* they kill rick */
248 if (e_rick_boxtest(e))
249 e_rick_gozombie();
250}
251
252
253/*
254 * Action function for e_them _t1a type (stays within boundaries)
255 *
256 * ASM 2452
257 */
258void
259e_them_t1a_action(U8 e)
260{
261 e_them_t1_action(e, TYPE_1A);
262}
263
264
265/*
266 * Action function for e_them _t1b type (runs for rick)
267 *
268 * ASM 21CA
269 */
270void
271e_them_t1b_action(U8 e)
272{
273 e_them_t1_action(e, TYPE_1B);
274}
275
276
277/*
278 * Action function for e_them _z (zombie) type
279 *
280 * ASM 23B8
281 */
282void
283e_them_z_action(U8 e)
284{
285#define offsx c1
286 U32 i;
287
288 /* calc new sprite */
289 ent_ents[e].sprite = ent_ents[e].sprbase
290 + ((ent_ents[e].x & 0x04) ? 0x07 : 0x06);
291
292 /* calc new y */
293 i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow;
294
295 /* deactivate if out of vertical boundaries */
296 if (ent_ents[e].y < 0 || ent_ents[e].y > 0x0140) {
297 ent_ents[e].n = 0;
298 return;
299 }
300
301 /* save */
302 ent_ents[e].offsy += 0x0080;
303 ent_ents[e].ylow = i;
304 ent_ents[e].y = i >> 8;
305
306 /* calc new x */
307 ent_ents[e].x += ent_ents[e].offsx;
308
309 /* must stay within horizontal boundaries */
310 if (ent_ents[e].x < 0)
311 ent_ents[e].x = 0;
312 if (ent_ents[e].x > 0xe8)
313 ent_ents[e].x = 0xe8;
314#undef offsx
315}
316
317
318/*
319 * Action sub-function for e_them _t2.
320 *
321 * Must document what it does.
322 *
323 * ASM 2792
324 */
325void
326e_them_t2_action2(U8 e)
327{
328#define flgclmb c1
329#define offsx c2
330 U32 i;
331 S16 x, y, yd;
332 U8 env0, env1;
333
334 /*
335 * vars required by the Black Magic (tm) performance at the
336 * end of this function.
337 */
338 static U16 bx;
339 static U8 *bl = (U8 *)&bx;
340 static U8 *bh = (U8 *)&bx + 1;
341 static U16 cx;
342 static U8 *cl = (U8 *)&cx;
343 static U8 *ch = (U8 *)&cx + 1;
344 static U16 *sl = (U16 *)&e_them_rndseed;
345 static U16 *sh = (U16 *)&e_them_rndseed + 2;
346
347 /*sys_printf("e_them_t2 ------------------------------\n");*/
348
349 /* latency: if not zero then decrease */
350 if (ent_ents[e].latency > 0) ent_ents[e].latency--;
351
352 /* climbing? */
353 if (!ent_ents[e].flgclmb) goto climbing_not;
354
355 /* CLIMBING */
356
357 /*sys_printf("e_them_t2 climbing\n");*/
358
359 /* latency: if not zero then return */
360 if (ent_ents[e].latency > 0) return;
361
362 /* calc new sprite */
363 ent_ents[e].sprite = ent_ents[e].sprbase + 0x08 +
364 (((ent_ents[e].x ^ ent_ents[e].y) & 0x04) ? 1 : 0);
365
366 /* reached rick's level? */
367 if ((ent_ents[e].y & 0xfe) != (E_RICK_ENT.y & 0xfe)) goto ymove;
368
369 xmove:
370 /* calc new x and test environment */
371 ent_ents[e].offsx = (ent_ents[e].x < E_RICK_ENT.x) ? 0x02 : -0x02;
372 x = ent_ents[e].x + ent_ents[e].offsx;
373 u_envtest(x, ent_ents[e].y, false, &env0, &env1);
374 if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))
375 return;
376 if (env1 & MAP_EFLG_LETHAL) {
377 e_them_gozombie(e);
378 return;
379 }
380 ent_ents[e].x = x;
381 if (env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB)) /* still climbing */
382 return;
383 goto climbing_not; /* not climbing anymore */
384
385 ymove:
386 /* calc new y and test environment */
387 yd = ent_ents[e].y < E_RICK_ENT.y ? 0x02 : -0x02;
388 y = ent_ents[e].y + yd;
389 if (y < 0 || y > 0x0140) {
390 ent_ents[e].n = 0;
391 return;
392 }
393 u_envtest(ent_ents[e].x, y, false, &env0, &env1);
394 if (env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP)) {
395 if (yd < 0)
396 goto xmove; /* can't go up */
397 else
398 goto climbing_not; /* can't go down */
399 }
400 /* can move */
401 ent_ents[e].y = y;
402 if (env1 & (MAP_EFLG_VERT|MAP_EFLG_CLIMB)) /* still climbing */
403 return;
404
405 /* NOT CLIMBING */
406
407 climbing_not:
408 /*sys_printf("e_them_t2 climbing NOT\n");*/
409
410 ent_ents[e].flgclmb = false; /* not climbing */
411
412 /* calc new y (falling) and test environment */
413 i = (ent_ents[e].y << 8) + ent_ents[e].offsy + ent_ents[e].ylow;
414 y = i >> 8;
415 u_envtest(ent_ents[e].x, y, false, &env0, &env1);
416 if (!(env1 & (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))) {
417 /*sys_printf("e_them_t2 y move OK\n");*/
418 /* can go there */
419 if (env1 & MAP_EFLG_LETHAL) {
420 e_them_gozombie(e);
421 return;
422 }
423 if (y > 0x0140) { /* deactivate if outside */
424 ent_ents[e].n = 0;
425 return;
426 }
427 if (!(env1 & MAP_EFLG_VERT)) {
428 /* save */
429 ent_ents[e].y = y;
430 ent_ents[e].ylow = i;
431 ent_ents[e].offsy += 0x0080;
432 if (ent_ents[e].offsy > 0x0800)
433 ent_ents[e].offsy = 0x0800;
434 return;
435 }
436 if (((ent_ents[e].x & 0x07) == 0x04) && (y < E_RICK_ENT.y)) {
437 /*sys_printf("e_them_t2 climbing00\n");*/
438 ent_ents[e].flgclmb = true; /* climbing */
439 return;
440 }
441 }
442
443 /*sys_printf("e_them_t2 ymove nok or ...\n");*/
444 /* can't go there, or ... */
445 ent_ents[e].y = (ent_ents[e].y & 0xf8) | 0x03; /* align to ground */
446 ent_ents[e].offsy = 0x0100;
447 if (ent_ents[e].latency != 00)
448 return;
449
450 if ((env1 & MAP_EFLG_CLIMB) &&
451 ((ent_ents[e].x & 0x0e) == 0x04) &&
452 (ent_ents[e].y > E_RICK_ENT.y)) {
453 /*sys_printf("e_them_t2 climbing01\n");*/
454 ent_ents[e].flgclmb = true; /* climbing */
455 return;
456 }
457
458 /* calc new sprite */
459 ent_ents[e].sprite = ent_ents[e].sprbase +
460 ent_sprseq[(ent_ents[e].offsx < 0 ? 4 : 0) +
461 ((ent_ents[e].x & 0x0e) >> 3)];
462 /*sys_printf("e_them_t2 sprite %02x\n", ent_ents[e].sprite);*/
463
464
465 /* */
466 if (ent_ents[e].offsx == 0)
467 ent_ents[e].offsx = 2;
468 x = ent_ents[e].x + ent_ents[e].offsx;
469 /*sys_printf("e_them_t2 xmove x=%02x\n", x);*/
470 if (x < 0xe8) {
471 u_envtest(x, ent_ents[e].y, false, &env0, &env1);
472 if (!(env1 & (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP))) {
473 ent_ents[e].x = x;
474 if ((x & 0x1e) != 0x08)
475 return;
476
477 /*
478 * Black Magic (tm)
479 *
480 * this is obviously some sort of randomizer to define a direction
481 * for the entity. it is an exact copy of what the assembler code
482 * does but I can't explain.
483 */
484 bx = e_them_rndnbr + *sh + *sl + 0x0d;
485 cx = *sh;
486 *bl ^= *ch;
487 *bl ^= *cl;
488 *bl ^= *bh;
489 e_them_rndnbr = bx;
490
491 ent_ents[e].offsx = (*bl & 0x01) ? -0x02 : 0x02;
492
493 /* back to normal */
494
495 return;
496
497 }
498 }
499
500 /* U-turn */
501 /*sys_printf("e_them_t2 u-turn\n");*/
502 if (ent_ents[e].offsx == 0)
503 ent_ents[e].offsx = 2;
504 else
505 ent_ents[e].offsx = -ent_ents[e].offsx;
506#undef offsx
507}
508
509/*
510 * Action function for e_them _t2 type
511 *
512 * ASM 2718
513 */
514void
515e_them_t2_action(U8 e)
516{
517 e_them_t2_action2(e);
518
519 /* they kill rick */
520 if (e_rick_boxtest(e))
521 e_rick_gozombie();
522
523 /* lethal entities kill them */
524 if (u_themtest(e)) {
525 e_them_gozombie(e);
526 return;
527 }
528
529 /* bullet kills them */
530 if (E_BULLET_ENT.n &&
531 u_fboxtest(e, E_BULLET_ENT.x + (e_bullet_offsx < 0 ? 00 : 0x18),
532 E_BULLET_ENT.y)) {
533 E_BULLET_ENT.n = 0;
534 e_them_gozombie(e);
535 return;
536 }
537
538 /* bomb kills them */
539 if (e_bomb_lethal && e_bomb_hit(e)) {
540 e_them_gozombie(e);
541 return;
542 }
543
544 /* rick stops them */
545 if (e_rick_state_test(E_RICK_STSTOP) &&
546 u_fboxtest(e, e_rick_stop_x, e_rick_stop_y))
547 ent_ents[e].latency = 0x14;
548}
549
550
551/*
552 * Action sub-function for e_them _t3
553 *
554 * FIXME always starts asleep??
555 *
556 * Waits until triggered by something, then execute move steps from
557 * ent_mvstep with sprite from ent_sprseq. When done, either restart
558 * or disappear.
559 *
560 * Not always lethal ... but if lethal, kills rick.
561 *
562 * ASM: 255A
563 */
564void
565e_them_t3_action2(U8 e)
566{
567#define sproffs c1
568#define step_count c2
569 U8 i;
570 S16 x, y;
571 int wav_index;
572
573 while (1) {
574
575 /* calc new sprite */
576 i = ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs];
577 if (i == 0xff)
578 i = ent_sprseq[ent_ents[e].sprbase];
579 ent_ents[e].sprite = i;
580
581 if (ent_ents[e].sproffs != 0) { /* awake */
582
583 /* rotate sprseq */
584 if (ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs] != 0xff)
585 ent_ents[e].sproffs++;
586 if (ent_sprseq[ent_ents[e].sprbase + ent_ents[e].sproffs] == 0xff)
587 ent_ents[e].sproffs = 1;
588
589 if (ent_ents[e].step_count < ent_mvstep[ent_ents[e].step_no].count) {
590 /*
591 * still running this step: try to increment x and y while
592 * checking that they remain within boudaries. if so, return.
593 * else switch to next step.
594 */
595 ent_ents[e].step_count++;
596 x = ent_ents[e].x + ent_mvstep[ent_ents[e].step_no].dx;
597
598 /* check'n save */
599 if (x > 0 && x < 0xe8) {
600 ent_ents[e].x = x;
601 /*FIXME*/
602 /*
603 y = ent_mvstep[ent_ents[e].step_no].dy;
604 if (y < 0)
605 y += 0xff00;
606 y += ent_ents[e].y;
607 */
608 y = ent_ents[e].y + ent_mvstep[ent_ents[e].step_no].dy;
609 if (y > 0 && y < 0x0140) {
610 ent_ents[e].y = y;
611 return;
612 }
613 }
614 }
615
616 /*
617 * step is done, or x or y is outside boundaries. try to
618 * switch to next step
619 */
620 ent_ents[e].step_no++;
621 if (ent_mvstep[ent_ents[e].step_no].count != 0xff) {
622 /* there is a next step: init and loop */
623 ent_ents[e].step_count = 0;
624 }
625 else {
626 /* there is no next step: restart or deactivate */
627 if (!e_rick_state_test(E_RICK_STZOMBIE) &&
628 !(ent_ents[e].flags & ENT_FLG_ONCE)) {
629 /* loop this entity */
630 ent_ents[e].sproffs = 0;
631 ent_ents[e].n &= ~ENT_LETHAL;
632 if (ent_ents[e].flags & ENT_FLG_LETHALR)
633 ent_ents[e].n |= ENT_LETHAL;
634 ent_ents[e].x = ent_ents[e].xsave;
635 ent_ents[e].y = ent_ents[e].ysave;
636 if (ent_ents[e].y < 0 || ent_ents[e].y > 0x140) {
637 ent_ents[e].n = 0;
638 return;
639 }
640 }
641 else {
642 /* deactivate this entity */
643 ent_ents[e].n = 0;
644 return;
645 }
646 }
647 }
648 else { /* ent_ents[e].sprseq1 == 0 -- waiting */
649
650 /* ugly GOTOs */
651
652 if (ent_ents[e].flags & ENT_FLG_TRIGRICK) { /* reacts to rick */
653 /* wake up if triggered by rick */
654 if (u_trigbox(e, E_RICK_ENT.x + 0x0C, E_RICK_ENT.y + 0x0A))
655 goto wakeup;
656 }
657
658 if (ent_ents[e].flags & ENT_FLG_TRIGSTOP) { /* reacts to rick "stop" */
659 /* wake up if triggered by rick "stop" */
660 if (e_rick_state_test(E_RICK_STSTOP) &&
661 u_trigbox(e, e_rick_stop_x, e_rick_stop_y))
662 goto wakeup;
663 }
664
665 if (ent_ents[e].flags & ENT_FLG_TRIGBULLET) { /* reacts to bullets */
666 /* wake up if triggered by bullet */
667 if (E_BULLET_ENT.n && u_trigbox(e, e_bullet_xc, e_bullet_yc)) {
668 E_BULLET_ENT.n = 0;
669 goto wakeup;
670 }
671 }
672
673 if (ent_ents[e].flags & ENT_FLG_TRIGBOMB) { /* reacts to bombs */
674 /* wake up if triggered by bomb */
675 if (e_bomb_lethal && u_trigbox(e, e_bomb_xc, e_bomb_yc))
676 goto wakeup;
677 }
678
679 /* not triggered: keep waiting */
680 return;
681
682 /* something triggered the entity: wake up */
683 /* initialize step counter */
684 wakeup:
685 if (e_rick_state_test(E_RICK_STZOMBIE))
686 {
687 return;
688 }
689#ifdef ENABLE_SOUND
690 /*
691 * FIXME the sound should come from a table, there are 10 of them
692 * but I dont have the table yet. must rip the data off the game...
693 * FIXME is it 8 of them, not 10?
694 * FIXME testing below...
695 */
696
697 /* FIXME this is defensive, need to figure out whether there
698 is simply missing sound (and possibly rip it)
699 or wrong data in sumbmap 47 (when making the switch explode)
700 and submap 13 (when touching jewel) */
701 wav_index = (ent_ents[e].trigsnd & 0x1F) - 0x14;
702 if((0 <= wav_index) && (wav_index < SOUNDS_NBR_ENTITIES - 1))
703 {
704 syssnd_play(soundEntity[wav_index], 1);
705 }
706 /*syssnd_play(WAV_ENTITY[0], 1);*/
707#endif /* ENABLE_SOUND */
708 ent_ents[e].n &= ~ENT_LETHAL;
709 if (ent_ents[e].flags & ENT_FLG_LETHALI)
710 ent_ents[e].n |= ENT_LETHAL;
711 ent_ents[e].sproffs = 1;
712 ent_ents[e].step_count = 0;
713 ent_ents[e].step_no = ent_ents[e].step_no_i;
714 return;
715 }
716 }
717#undef step_count
718}
719
720
721/*
722 * Action function for e_them _t3 type
723 *
724 * ASM 2546
725 */
726void
727e_them_t3_action(U8 e)
728{
729 e_them_t3_action2(e);
730
731 /* if lethal, can kill rick */
732 if ((ent_ents[e].n & ENT_LETHAL) &&
733 !e_rick_state_test(E_RICK_STZOMBIE) && e_rick_boxtest(e)) { /* CALL 1130 */
734 e_rick_gozombie();
735 }
736}
737
738/* eof */
diff --git a/apps/plugins/xrick/e_them.h b/apps/plugins/xrick/e_them.h
new file mode 100644
index 0000000000..7b524142f6
--- /dev/null
+++ b/apps/plugins/xrick/e_them.h
@@ -0,0 +1,31 @@
1/*
2 * xrick/e_them.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _E_THEM_H
17#define _E_THEM_H
18
19#include "xrick/system/basic_types.h"
20
21extern U32 e_them_rndseed;
22
23extern void e_them_t1a_action(U8);
24extern void e_them_t1b_action(U8);
25extern void e_them_t2_action(U8);
26extern void e_them_t3_action(U8);
27extern void e_them_z_action(U8);
28
29#endif /* ndef _E_THEM_H */
30
31/* eof */
diff --git a/apps/plugins/xrick/ents.c b/apps/plugins/xrick/ents.c
new file mode 100644
index 0000000000..5e35f2bdd1
--- /dev/null
+++ b/apps/plugins/xrick/ents.c
@@ -0,0 +1,540 @@
1/*
2 * xrick/ents.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/ents.h"
17
18#include "xrick/config.h"
19#include "xrick/control.h"
20#include "xrick/game.h"
21#include "xrick/debug.h"
22#include "xrick/e_bullet.h"
23#include "xrick/e_bomb.h"
24#include "xrick/e_rick.h"
25#include "xrick/e_them.h"
26#include "xrick/e_bonus.h"
27#include "xrick/e_box.h"
28#include "xrick/e_sbonus.h"
29#include "xrick/rects.h"
30#include "xrick/maps.h"
31#include "xrick/draw.h"
32
33#include <stdlib.h> /* abs */
34
35/*
36 * global vars
37 */
38ent_t ent_ents[ENT_ENTSNUM + 1];
39
40size_t ent_nbr_entdata = 0;
41entdata_t *ent_entdata = NULL;
42
43rect_t *ent_rects = NULL;
44
45size_t ent_nbr_sprseq = 0;
46U8 *ent_sprseq = NULL;
47
48size_t ent_nbr_mvstep = 0;
49mvstep_t *ent_mvstep = NULL;
50
51/*
52 * prototypes
53 */
54static void ent_addrect(S16, S16, U16, U16);
55static bool ent_creat1(U8 *);
56static bool ent_creat2(U8 *, U16);
57
58
59/*
60 * Reset entities
61 *
62 * ASM 2520
63 */
64void
65ent_reset(void)
66{
67 U8 i;
68
69 e_rick_state_clear(E_RICK_STSTOP);
70 e_bomb_lethal = false;
71
72 ent_ents[0].n = 0;
73 for (i = 2; ent_ents[i].n != 0xff; i++)
74 ent_ents[i].n = 0;
75}
76
77
78/*
79 * Create an entity on slots 4 to 8 by using the first slot available.
80 * Entities of type e_them on slots 4 to 8, when lethal, can kill
81 * other e_them (on slots 4 to C) as well as rick.
82 *
83 * ASM 209C
84 *
85 * e: anything, CHANGED to the allocated entity number.
86 * return: true/OK false/not
87 */
88static bool
89ent_creat1(U8 *e)
90{
91 /* look for a slot */
92 for (*e = 0x04; *e < 0x09; (*e)++)
93 if (ent_ents[*e].n == 0) { /* if slot available, use it */
94 ent_ents[*e].c1 = 0;
95 return true;
96 }
97
98 return false;
99}
100
101
102/*
103 * Create an entity on slots 9 to C by using the first slot available.
104 * Entities of type e_them on slots 9 to C can kill rick when lethal,
105 * but they can never kill other e_them.
106 *
107 * ASM 20BC
108 *
109 * e: anything, CHANGED to the allocated entity number.
110 * m: number of the mark triggering the creation of the entity.
111 * ret: true/OK false/not
112 */
113static bool
114ent_creat2(U8 *e, U16 m)
115{
116 /* make sure the entity created by this mark is not active already */
117 for (*e = 0x09; *e < 0x0c; (*e)++)
118 if (ent_ents[*e].n != 0 && ent_ents[*e].mark == m)
119 return false;
120
121 /* look for a slot */
122 for (*e = 0x09; *e < 0x0c; (*e)++)
123 if (ent_ents[*e].n == 0) { /* if slot available, use it */
124 ent_ents[*e].c1 = 2;
125 return true;
126 }
127
128 return false;
129}
130
131
132/*
133 * Process marks that are within the visible portion of the map,
134 * and create the corresponding entities.
135 *
136 * absolute map coordinate means that they are not relative to
137 * map_frow, as any other coordinates are.
138 *
139 * ASM 1F40
140 *
141 * frow: first visible row of the map -- absolute map coordinate
142 * lrow: last visible row of the map -- absolute map coordinate
143 */
144void
145ent_actvis(U8 frow, U8 lrow)
146{
147 U16 m;
148 U8 e;
149 U16 y;
150
151 /*
152 * go through the list and find the first mark that
153 * is visible, i.e. which has a row greater than the
154 * first row (marks being ordered by row number).
155 */
156 for (m = map_submaps[game_submap].mark;
157 map_marks[m].row != 0xff && map_marks[m].row < frow;
158 m++);
159
160 if (map_marks[m].row == 0xff) /* none found */
161 return;
162
163 /*
164 * go through the list and process all marks that are
165 * visible, i.e. which have a row lower than the last
166 * row (marks still being ordered by row number).
167 */
168 for (;
169 map_marks[m].row != 0xff && map_marks[m].row < lrow;
170 m++) {
171
172 /* ignore marks that are not active */
173 if (map_marks[m].ent & MAP_MARK_NACT)
174 continue;
175
176 /*
177 * allocate a slot to the new entity
178 *
179 * slot type
180 * 0 available for e_them (lethal to other e_them, and stops entities
181 * i.e. entities can't move over them. E.g. moving blocks. But they
182 * can move over entities and kill them!).
183 * 1 xrick
184 * 2 bullet
185 * 3 bomb
186 * 4-8 available for e_them, e_box, e_bonus or e_sbonus (lethal to
187 * other e_them, identified by their number being >= 0x10)
188 * 9-C available for e_them, e_box, e_bonus or e_sbonus (not lethal to
189 * other e_them, identified by their number being < 0x10)
190 *
191 * the type of an entity is determined by its .n as detailed below.
192 *
193 * 1 xrick
194 * 2 bullet
195 * 3 bomb
196 * 4, 7, a, d e_them, type 1a
197 * 5, 8, b, e e_them, type 1b
198 * 6, 9, c, f e_them, type 2
199 * 10, 11 box
200 * 12, 13, 14, 15 bonus
201 * 16, 17 speed bonus
202 * >17 e_them, type 3
203 * 47 zombie
204 */
205
206 if (!(map_marks[m].flags & ENT_FLG_STOPRICK)) {
207 if (map_marks[m].ent >= 0x10) {
208 /* boxes, bonuses and type 3 e_them go to slot 4-8 */
209 /* (c1 set to 0 -> all type 3 e_them are sleeping) */
210 if (!ent_creat1(&e)) continue;
211 }
212 else {
213 /* type 1 and 2 e_them go to slot 9-c */
214 /* (c1 set to 2) */
215 if (!ent_creat2(&e, m)) continue;
216 }
217 }
218 else {
219 /* entities stopping rick (e.g. blocks) go to slot 0 */
220 if (ent_ents[0].n) continue;
221 e = 0;
222 ent_ents[0].c1 = 0;
223 }
224
225 /*
226 * initialize the entity
227 */
228 ent_ents[e].mark = m;
229 ent_ents[e].flags = map_marks[m].flags;
230 ent_ents[e].n = map_marks[m].ent;
231
232 /*
233 * if entity is to be already running (i.e. not asleep and waiting
234 * for some trigger to move), then use LETHALR i.e. restart flag, right
235 * from the beginning
236 */
237 if (ent_ents[e].flags & ENT_FLG_LETHALR)
238 ent_ents[e].n |= ENT_LETHAL;
239
240 ent_ents[e].x = map_marks[m].xy & 0xf8;
241
242 y = (map_marks[m].xy & 0x07) + (map_marks[m].row & 0xf8) - map_frow;
243 y <<= 3;
244 if (!(ent_ents[e].flags & ENT_FLG_STOPRICK))
245 y += 3;
246 ent_ents[e].y = y;
247
248 ent_ents[e].xsave = ent_ents[e].x;
249 ent_ents[e].ysave = ent_ents[e].y;
250
251 /*ent_ents[e].w0C = 0;*/ /* in ASM code but never used */
252
253 ent_ents[e].w = ent_entdata[map_marks[m].ent].w;
254 ent_ents[e].h = ent_entdata[map_marks[m].ent].h;
255 ent_ents[e].sprbase = ent_entdata[map_marks[m].ent].spr;
256 ent_ents[e].step_no_i = ent_entdata[map_marks[m].ent].sni;
257 ent_ents[e].trigsnd = (U8)ent_entdata[map_marks[m].ent].snd;
258
259 /*
260 * FIXME what is this? when all trigger flags are up, then
261 * use .sni for sprbase. Why? What is the point? (This is
262 * for type 1 and 2 e_them, ...)
263 *
264 * This also means that as long as sprite has not been
265 * recalculated, a wrong value is used. This is normal, see
266 * what happens to the falling guy on the right on submap 3:
267 * it changes when hitting the ground.
268 *
269 * Note: sprite recalculation has been fixed, refer to the commit log.
270 */
271#define ENT_FLG_TRIGGERS \
272(ENT_FLG_TRIGBOMB|ENT_FLG_TRIGBULLET|ENT_FLG_TRIGSTOP|ENT_FLG_TRIGRICK)
273 if ((ent_ents[e].flags & ENT_FLG_TRIGGERS) == ENT_FLG_TRIGGERS
274 && e >= 0x09)
275 ent_ents[e].sprbase = (U8)(ent_entdata[map_marks[m].ent].sni & 0x00ff);
276#undef ENT_FLG_TRIGGERS
277
278 ent_ents[e].sprite = (U8)ent_ents[e].sprbase;
279 ent_ents[e].trig_x = map_marks[m].lt & 0xf8;
280 ent_ents[e].latency = (map_marks[m].lt & 0x07) << 5; /* <<5 eq *32 */
281
282 ent_ents[e].trig_y = 3 + 8 * ((map_marks[m].row & 0xf8) - map_frow +
283 (map_marks[m].lt & 0x07));
284
285 ent_ents[e].c2 = 0;
286 ent_ents[e].offsy = 0;
287 ent_ents[e].ylow = 0;
288
289 ent_ents[e].front = false;
290
291 }
292}
293
294
295/*
296 * Add a tile-aligned rectangle containing the given rectangle (indicated
297 * by its MAP coordinates) to the list of rectangles. Clip the rectangle
298 * so it fits into the display zone.
299 */
300static void
301ent_addrect(S16 x, S16 y, U16 width, U16 height)
302{
303 S16 x0, y0;
304 U16 w0, h0;
305 rect_t *r;
306
307 /*sys_printf("rect %#04x,%#04x %#04x %#04x ", x, y, width, height);*/
308
309 /* align to tiles */
310 x0 = x & 0xfff8;
311 y0 = y & 0xfff8;
312 w0 = width;
313 h0 = height;
314 if (x - x0) w0 = (w0 + (x - x0)) | 0x0007;
315 if (y - y0) h0 = (h0 + (y - y0)) | 0x0007;
316
317 /* clip */
318 if (draw_clipms(&x0, &y0, &w0, &h0)) { /* do not add if fully clipped */
319 /*sys_printf("-> [clipped]\n");*/
320 return;
321 }
322
323 /*sys_printf("-> %#04x,%#04x %#04x %#04x\n", x0, y0, w0, h0);*/
324
325#ifdef GFXST
326 y0 += 8;
327#endif
328
329 /* get to screen */
330 x0 -= DRAW_XYMAP_SCRLEFT;
331 y0 -= DRAW_XYMAP_SCRTOP;
332
333 /* add rectangle to the list */
334 r = rects_new(x0, y0, w0, h0, ent_rects);
335 if (!r)
336 {
337 control_set(Control_EXIT);
338 return;
339 }
340 ent_rects = r;
341}
342
343
344/*
345 * Draw all entities onto the frame buffer.
346 *
347 * ASM 07a4
348 *
349 * NOTE This may need to be part of draw.c. Also needs better comments,
350 * NOTE and probably better rectangles management.
351 */
352void
353ent_draw(void)
354{
355 U8 i;
356#ifdef ENABLE_CHEATS
357 static bool ch3 = false;
358#endif
359 S16 dx, dy;
360
361 draw_tilesBank = map_tilesBank;
362
363 /* reset rectangles list */
364 rects_free(ent_rects);
365 ent_rects = NULL;
366
367 /*sys_printf("\n");*/
368
369 /*
370 * background loop : erase all entities that were visible
371 */
372 for (i = 0; ent_ents[i].n != 0xff; i++) {
373#ifdef ENABLE_CHEATS
374 if (ent_ents[i].prev_n && (ch3 || ent_ents[i].prev_s))
375#else
376 if (ent_ents[i].prev_n && ent_ents[i].prev_s)
377#endif
378 /* if entity was active, then erase it (redraw the map) */
379 draw_spriteBackground(ent_ents[i].prev_x, ent_ents[i].prev_y);
380 }
381
382 /*
383 * foreground loop : draw all entities that are visible
384 */
385 for (i = 0; ent_ents[i].n != 0xff; i++) {
386 /*
387 * If entity is active now, draw the sprite. If entity was
388 * not active before, add a rectangle for the sprite.
389 */
390#ifdef ENABLE_CHEATS
391 if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite))
392#else
393 if (ent_ents[i].n && ent_ents[i].sprite)
394#endif
395 /* If entitiy is active, draw the sprite. */
396 draw_sprite2(ent_ents[i].sprite,
397 ent_ents[i].x, ent_ents[i].y,
398 ent_ents[i].front);
399 }
400
401 /*
402 * rectangles loop : figure out which parts of the screen have been
403 * impacted and need to be refreshed, then save state
404 */
405 for (i = 0; ent_ents[i].n != 0xff; i++) {
406#ifdef ENABLE_CHEATS
407 if (ent_ents[i].prev_n && (ch3 || ent_ents[i].prev_s)) {
408#else
409 if (ent_ents[i].prev_n && ent_ents[i].prev_s) {
410#endif
411 /* (1) if entity was active and has been drawn ... */
412#ifdef ENABLE_CHEATS
413 if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite)) {
414#else
415 if (ent_ents[i].n && ent_ents[i].sprite) {
416#endif
417 /* (1.1) ... and is still active now and still needs to be drawn, */
418 /* then check if rectangles intersect */
419 dx = abs(ent_ents[i].x - ent_ents[i].prev_x);
420 dy = abs(ent_ents[i].y - ent_ents[i].prev_y);
421 if (dx < 0x20 && dy < 0x16) {
422 /* (1.1.1) if they do, then create one rectangle */
423 ent_addrect((ent_ents[i].prev_x < ent_ents[i].x)
424 ? ent_ents[i].prev_x : ent_ents[i].x,
425 (ent_ents[i].prev_y < ent_ents[i].y)
426 ? ent_ents[i].prev_y : ent_ents[i].y,
427 dx + 0x20, dy + 0x15);
428 }
429 else {
430 /* (1.1.2) else, create two rectangles */
431 ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15);
432 ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15);
433 }
434 }
435 else
436 /* (1.2) ... and is not active anymore or does not need to be drawn */
437 /* then create one single rectangle */
438 ent_addrect(ent_ents[i].prev_x, ent_ents[i].prev_y, 0x20, 0x15);
439 }
440#ifdef ENABLE_CHEATS
441 else if (ent_ents[i].n && (game_cheat3 || ent_ents[i].sprite)) {
442#else
443 else if (ent_ents[i].n && ent_ents[i].sprite) {
444#endif
445 /* (2) if entity is active and needs to be drawn, */
446 /* then create one rectangle */
447 ent_addrect(ent_ents[i].x, ent_ents[i].y, 0x20, 0x15);
448 }
449
450 /* save state */
451 ent_ents[i].prev_x = ent_ents[i].x;
452 ent_ents[i].prev_y = ent_ents[i].y;
453 ent_ents[i].prev_n = ent_ents[i].n;
454 ent_ents[i].prev_s = ent_ents[i].sprite;
455 }
456
457#ifdef ENABLE_CHEATS
458 ch3 = game_cheat3;
459#endif
460}
461
462
463/*
464 * Clear entities previous state
465 *
466 */
467void
468ent_clprev(void)
469{
470 U8 i;
471
472 for (i = 0; ent_ents[i].n != 0xff; i++)
473 ent_ents[i].prev_n = 0;
474}
475
476/*
477 * Table containing entity action function pointers.
478 */
479void (*ent_actf[])(U8) = {
480 NULL, /* 00 - zero means that the slot is free */
481 e_rick_action, /* 01 - 12CA */
482 e_bullet_action, /* 02 - 1883 */
483 e_bomb_action, /* 03 - 18CA */
484 e_them_t1a_action, /* 04 - 2452 */
485 e_them_t1b_action, /* 05 - 21CA */
486 e_them_t2_action, /* 06 - 2718 */
487 e_them_t1a_action, /* 07 - 2452 */
488 e_them_t1b_action, /* 08 - 21CA */
489 e_them_t2_action, /* 09 - 2718 */
490 e_them_t1a_action, /* 0A - 2452 */
491 e_them_t1b_action, /* 0B - 21CA */
492 e_them_t2_action, /* 0C - 2718 */
493 e_them_t1a_action, /* 0D - 2452 */
494 e_them_t1b_action, /* 0E - 21CA */
495 e_them_t2_action, /* 0F - 2718 */
496 e_box_action, /* 10 - 245A */
497 e_box_action, /* 11 - 245A */
498 e_bonus_action, /* 12 - 242C */
499 e_bonus_action, /* 13 - 242C */
500 e_bonus_action, /* 14 - 242C */
501 e_bonus_action, /* 15 - 242C */
502 e_sbonus_start, /* 16 - 2182 */
503 e_sbonus_stop /* 17 - 2143 */
504};
505
506
507/*
508 * Run entities action function
509 *
510 */
511void
512ent_action(void)
513{
514 U8 i, k;
515
516 IFDEBUG_ENTS(
517 sys_printf("xrick/ents: --------- action ----------------\n");
518 for (i = 0; ent_ents[i].n != 0xff; i++)
519 if (ent_ents[i].n) {
520 sys_printf("xrick/ents: slot %#04x, entity %#04x", i, ent_ents[i].n);
521 sys_printf(" (%#06x, %#06x), sprite %#04x.\n",
522 ent_ents[i].x, ent_ents[i].y, ent_ents[i].sprite);
523 }
524 );
525
526 for (i = 0; ent_ents[i].n != 0xff; i++) {
527 if (ent_ents[i].n) {
528 k = ent_ents[i].n & 0x7f;
529 if (k == 0x47)
530 e_them_z_action(i);
531 else if (k >= 0x18)
532 e_them_t3_action(i);
533 else
534 ent_actf[k](i);
535 }
536 }
537}
538
539
540/* eof */
diff --git a/apps/plugins/xrick/ents.h b/apps/plugins/xrick/ents.h
new file mode 100644
index 0000000000..1014205035
--- /dev/null
+++ b/apps/plugins/xrick/ents.h
@@ -0,0 +1,118 @@
1/*
2 * xrick/ents.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _ENTS_H
17#define _ENTS_H
18
19#include "xrick/rects.h"
20
21#include <stddef.h> /* size_t */
22
23#define ENT_XRICK ent_ents[1]
24
25/*
26 * flags for ent_ents[e].n ("yes" when set)
27 *
28 * ENT_LETHAL: is entity lethal?
29 */
30#define ENT_LETHAL 0x80
31
32/*
33 * flags for ent_ents[e].flag ("yes" when set)
34 *
35 * ENT_FLG_ONCE: should the entity run once only?
36 * ENT_FLG_STOPRICK: does the entity stops rick (and goes to slot zero)?
37 * ENT_FLG_LETHALR: is entity lethal when restarting?
38 * ENT_FLG_LETHALI: is entity initially lethal?
39 * ENT_FLG_TRIGBOMB: can entity be triggered by a bomb?
40 * ENT_FLG_TRIGBULLET: can entity be triggered by a bullet?
41 * ENT_FLG_TRIGSTOP: can entity be triggered by rick stop?
42 * ENT_FLG_TRIGRICK: can entity be triggered by rick?
43 */
44#define ENT_FLG_ONCE 0x01
45#define ENT_FLG_STOPRICK 0x02
46#define ENT_FLG_LETHALR 0x04
47#define ENT_FLG_LETHALI 0x08
48#define ENT_FLG_TRIGBOMB 0x10
49#define ENT_FLG_TRIGBULLET 0x20
50#define ENT_FLG_TRIGSTOP 0x40
51#define ENT_FLG_TRIGRICK 0x80
52
53typedef struct {
54 U8 n; /* b00 */
55 /*U8 b01;*/ /* b01 in ASM code but never used */
56 S16 x; /* b02 - position */
57 S16 y; /* w04 - position */
58 U8 sprite; /* b08 - sprite number */
59 /*U16 w0C;*/ /* w0C in ASM code but never used */
60 U8 w; /* b0E - width */
61 U8 h; /* b10 - height */
62 U16 mark; /* w12 - number of the mark that created the entity */
63 U8 flags; /* b14 */
64 S16 trig_x; /* b16 - position of trigger box */
65 S16 trig_y; /* w18 - position of trigger box */
66 S16 xsave; /* b1C */
67 S16 ysave; /* w1E */
68 U16 sprbase; /* w20 */
69 U16 step_no_i; /* w22 */
70 U16 step_no; /* w24 */
71 S16 c1; /* b26 */
72 S16 c2; /* b28 */
73 U8 ylow; /* b2A */
74 S16 offsy; /* w2C */
75 U8 latency; /* b2E */
76 U8 prev_n; /* new */
77 S16 prev_x; /* new */
78 S16 prev_y; /* new */
79 U8 prev_s; /* new */
80 bool front; /* new */
81 U8 trigsnd; /* new */
82} ent_t;
83
84typedef struct {
85 U8 w, h;
86 U16 spr, sni;
87 U8 trig_w, trig_h;
88 U8 snd;
89} entdata_t;
90
91typedef struct {
92 U8 count;
93 S8 dx, dy;
94} mvstep_t;
95
96enum { ENT_ENTSNUM = 12 };
97extern ent_t ent_ents[ENT_ENTSNUM + 1];
98
99extern size_t ent_nbr_entdata;
100extern entdata_t *ent_entdata;
101
102extern rect_t *ent_rects;
103
104extern size_t ent_nbr_sprseq;
105extern U8 *ent_sprseq;
106
107extern size_t ent_nbr_mvstep;
108extern mvstep_t *ent_mvstep;
109
110extern void ent_reset(void);
111extern void ent_actvis(U8, U8);
112extern void ent_draw(void);
113extern void ent_clprev(void);
114extern void ent_action(void);
115
116#endif /* ndef _ENTS_H */
117
118/* eof */
diff --git a/apps/plugins/xrick/game.c b/apps/plugins/xrick/game.c
new file mode 100644
index 0000000000..ac99c1829e
--- /dev/null
+++ b/apps/plugins/xrick/game.c
@@ -0,0 +1,722 @@
1/*
2 * xrick/game.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/game.h"
17
18#include "xrick/draw.h"
19#include "xrick/maps.h"
20#include "xrick/ents.h"
21#include "xrick/e_rick.h"
22#include "xrick/e_sbonus.h"
23#include "xrick/e_them.h"
24#include "xrick/screens.h"
25#include "xrick/rects.h"
26#include "xrick/scroller.h"
27#include "xrick/control.h"
28#include "xrick/resources.h"
29
30#ifdef ENABLE_DEVTOOLS
31#include "xrick/devtools.h"
32#endif
33
34
35/*
36 * local typedefs
37 */
38typedef enum {
39#ifdef ENABLE_DEVTOOLS
40 DEVTOOLS,
41#endif
42 XRICK,
43 INIT_GAME, INIT_BUFFER,
44 INTRO_MAIN, INTRO_MAP,
45 PAUSE_PRESSED1, PAUSE_PRESSED1B, PAUSED, PAUSE_PRESSED2,
46 PLAY0, PLAY1, PLAY2, PLAY3,
47 CHAIN_SUBMAP, CHAIN_MAP, CHAIN_END,
48 SCROLL_UP, SCROLL_DOWN,
49 RESTART, GAMEOVER, GETNAME, EXIT
50} game_state_t;
51
52
53/*
54 * global vars
55 */
56U8 game_period = 0;
57bool game_waitevt = false;
58const rect_t *game_rects = NULL;
59
60U8 game_lives = 0;
61U8 game_bombs = 0;
62U8 game_bullets = 0;
63U32 game_score = 0;
64
65U16 game_map = 0;
66U16 game_submap = 0;
67
68U8 game_dir = RIGHT;
69bool game_chsm = false;
70
71bool game_cheat1 = false;
72bool game_cheat2 = false;
73bool game_cheat3 = false;
74
75
76/*
77 * local vars
78 */
79static U8 isave_frow;
80static game_state_t game_state;
81#ifdef ENABLE_SOUND
82static sound_t *currentMusic = NULL;
83#endif
84
85
86/*
87 * prototypes
88 */
89static void frame(void);
90static void init(void);
91static void play0(void);
92static void play3(void);
93static void restart(void);
94static void isave(void);
95static void irestore(void);
96
97
98/*
99 * Cheats
100 */
101#ifdef ENABLE_CHEATS
102void
103game_toggleCheat(cheat_t cheat)
104{
105 if (game_state != INTRO_MAIN && game_state != INTRO_MAP &&
106 game_state != GAMEOVER && game_state != GETNAME &&
107#ifdef ENABLE_DEVTOOLS
108 game_state != DEVTOOLS &&
109#endif
110 game_state != XRICK && game_state != EXIT)
111 {
112 switch (cheat)
113 {
114 case Cheat_UNLIMITED_ALL:
115 {
116 game_cheat1 = !game_cheat1;
117 game_lives = 6;
118 game_bombs = 6;
119 game_bullets = 6;
120 break;
121 }
122 case Cheat_NEVER_DIE:
123 {
124 game_cheat2 = !game_cheat2;
125 break;
126 }
127 case Cheat_EXPOSE:
128 {
129 game_cheat3 = !game_cheat3;
130 break;
131 }
132 }
133 draw_infos();
134 /* FIXME this should probably only raise a flag ... */
135 /* plus we only need to update INFORECT not the whole screen */
136 sysvid_update(&draw_SCREENRECT);
137 }
138}
139#endif
140
141#ifdef ENABLE_SOUND
142/*
143 * Music
144 */
145void
146game_setmusic(sound_t * newMusic, S8 loop)
147{
148 if (!newMusic)
149 {
150 return;
151 }
152
153 if (currentMusic)
154 {
155 game_stopmusic();
156 }
157
158 syssnd_play(newMusic, loop);
159
160 currentMusic = newMusic;
161}
162
163void
164game_stopmusic(void)
165{
166 syssnd_stop(currentMusic);
167 currentMusic = NULL;
168}
169#endif /*ENABLE_SOUND */
170
171/*
172 * Main loop
173 */
174void
175game_run(void)
176{
177 U32 currentTime,
178#ifdef ENABLE_SOUND
179 lastSoundTime = 0,
180#endif
181 lastFrameTime = 0;
182
183 if (!resources_load())
184 {
185 resources_unload();
186 return;
187 }
188
189 if (!sys_cacheData())
190 {
191 sys_uncacheData();
192 return;
193 }
194
195 game_period = sysarg_args_period ? sysarg_args_period : GAME_PERIOD;
196 game_state = XRICK;
197
198 /* main loop */
199 while (game_state != EXIT)
200 {
201 currentTime = sys_gettime();
202
203 if (currentTime - lastFrameTime >= game_period)
204 {
205 /* frame */
206 frame();
207
208 /* video */
209 /*DEBUG*//*game_rects=&draw_SCREENRECT;*//*DEBUG*/
210 sysvid_update(game_rects);
211
212 /* reset rectangles list */
213 rects_free(ent_rects);
214 ent_rects = NULL;
215 draw_STATUSRECT.next = NULL; /* FIXME freerects should handle this */
216
217 /* events */
218 if (game_waitevt)
219 {
220 sysevt_wait(); /* wait for an event */
221 }
222 else
223 {
224 sysevt_poll(); /* process events (non-blocking) */
225 }
226
227 lastFrameTime = currentTime;
228 }
229
230#ifdef ENABLE_SOUND
231 if (currentTime - lastSoundTime >= syssnd_period)
232 {
233 /* sound */
234 syssnd_update();
235
236 lastSoundTime = currentTime;
237 }
238#endif /* ENABLE_SOUND */
239
240 sys_yield();
241 }
242
243#ifdef ENABLE_SOUND
244 syssnd_stopAll();
245#endif
246
247 sys_uncacheData();
248
249 resources_unload();
250}
251
252/*
253 * Prepare frame
254 *
255 * This function loops forever: use 'return' when a frame is ready.
256 * When returning, game_rects must contain every parts of the buffer
257 * that have been modified.
258 */
259static void
260frame(void)
261{
262 while (1) {
263
264 switch (game_state) {
265
266
267
268#ifdef ENABLE_DEVTOOLS
269 case DEVTOOLS:
270 switch (devtools_run()) {
271 case SCREEN_RUNNING:
272 return;
273 case SCREEN_DONE:
274 game_state = INIT_GAME;
275 break;
276 case SCREEN_EXIT:
277 game_state = EXIT;
278 return;
279 }
280 break;
281#endif
282
283
284
285 case XRICK:
286 switch(screen_xrick()) {
287 case SCREEN_RUNNING:
288 return;
289 case SCREEN_DONE:
290#ifdef ENABLE_DEVTOOLS
291 game_state = DEVTOOLS;
292#else
293 game_state = INIT_GAME;
294#endif
295 break;
296 case SCREEN_EXIT:
297 game_state = EXIT;
298 return;
299 }
300 break;
301
302
303
304 case INIT_GAME:
305 init();
306 game_state = INTRO_MAIN;
307 break;
308
309
310
311 case INTRO_MAIN:
312 switch (screen_introMain()) {
313 case SCREEN_RUNNING:
314 return;
315 case SCREEN_DONE:
316 game_state = INTRO_MAP;
317 break;
318 case SCREEN_EXIT:
319 game_state = EXIT;
320 return;
321 }
322 break;
323
324
325
326 case INTRO_MAP:
327 switch (screen_introMap()) {
328 case SCREEN_RUNNING:
329 return;
330 case SCREEN_DONE:
331 game_waitevt = false;
332 game_state = INIT_BUFFER;
333 break;
334 case SCREEN_EXIT:
335 game_state = EXIT;
336 return;
337 }
338 break;
339
340
341
342 case INIT_BUFFER:
343 sysvid_clear(); /* clear buffer */
344 draw_map(); /* draw the map onto the buffer */
345 draw_drawStatus(); /* draw the status bar onto the buffer */
346#ifdef ENABLE_CHEATS
347 draw_infos(); /* draw the info bar onto the buffer */
348#endif
349 game_rects = &draw_SCREENRECT; /* request full buffer refresh */
350 game_state = PLAY0;
351 return;
352
353
354
355 case PAUSE_PRESSED1:
356 screen_pause(true);
357 game_state = PAUSE_PRESSED1B;
358 break;
359
360
361
362 case PAUSE_PRESSED1B:
363 if (control_test(Control_PAUSE))
364 return;
365 game_state = PAUSED;
366 break;
367
368
369
370 case PAUSED:
371 if (control_test(Control_PAUSE))
372 game_state = PAUSE_PRESSED2;
373 if (control_test(Control_EXIT))
374 game_state = EXIT;
375 return;
376
377
378
379 case PAUSE_PRESSED2:
380 if (!(control_test(Control_PAUSE))) {
381 game_waitevt = false;
382 screen_pause(false);
383#ifdef ENABLE_SOUND
384 syssnd_pauseAll(false);
385#endif
386 game_state = PLAY2;
387 }
388 return;
389
390
391
392 case PLAY0:
393 play0();
394 break;
395
396
397
398 case PLAY1:
399 if (control_test(Control_PAUSE)) {
400#ifdef ENABLE_SOUND
401 syssnd_pauseAll(true);
402#endif
403 game_waitevt = true;
404 game_state = PAUSE_PRESSED1;
405 }
406 else if (!control_active) {
407#ifdef ENABLE_SOUND
408 syssnd_pauseAll(true);
409#endif
410 game_waitevt = true;
411 screen_pause(true);
412 game_state = PAUSED;
413 }
414 else
415 game_state = PLAY2;
416 break;
417
418
419
420 case PLAY2:
421 if (e_rick_state_test(E_RICK_STDEAD)) { /* rick is dead */
422 if (game_cheat1 || --game_lives) {
423 game_state = RESTART;
424 } else {
425 game_state = GAMEOVER;
426 }
427 }
428 else if (game_chsm) /* request to chain to next submap */
429 game_state = CHAIN_SUBMAP;
430 else
431 game_state = PLAY3;
432 break;
433
434
435
436 case PLAY3:
437 play3();
438 return;
439
440
441
442 case CHAIN_SUBMAP:
443 if (map_chain())
444 game_state = CHAIN_END;
445 else {
446 game_bullets = 0x06;
447 game_bombs = 0x06;
448 game_map++;
449
450 if (game_map == map_nbr_maps - 1) {
451 /* reached end of game */
452 /* FIXME @292?*/
453 }
454
455 game_state = CHAIN_MAP;
456 }
457 break;
458
459
460
461 case CHAIN_MAP: /* CHAIN MAP */
462 switch (screen_introMap()) {
463 case SCREEN_RUNNING:
464 return;
465 case SCREEN_DONE:
466 if (game_map >= map_nbr_maps - 1) { /* reached end of game */
467 sysarg_args_map = 0;
468 sysarg_args_submap = 0;
469 game_state = GAMEOVER;
470 }
471 else { /* initialize game */
472 ent_ents[1].x = map_maps[game_map].x;
473 ent_ents[1].y = map_maps[game_map].y;
474 map_frow = (U8)map_maps[game_map].row;
475 game_submap = map_maps[game_map].submap;
476 game_state = CHAIN_END;
477 }
478 break;
479 case SCREEN_EXIT:
480 game_state = EXIT;
481 return;
482 }
483 break;
484
485
486
487 case CHAIN_END:
488 map_init(); /* initialize the map */
489 isave(); /* save data in case of a restart */
490 ent_clprev(); /* cleanup entities */
491 draw_map(); /* draw the map onto the buffer */
492 draw_drawStatus(); /* draw the status bar onto the buffer */
493 game_rects = &draw_SCREENRECT; /* request full screen refresh */
494 game_state = PLAY0;
495 return;
496
497
498
499 case SCROLL_UP:
500 switch (scroll_up()) {
501 case SCROLL_RUNNING:
502 return;
503 case SCROLL_DONE:
504 game_state = PLAY0;
505 break;
506 }
507 break;
508
509
510
511 case SCROLL_DOWN:
512 switch (scroll_down()) {
513 case SCROLL_RUNNING:
514 return;
515 case SCROLL_DONE:
516 game_state = PLAY0;
517 break;
518 }
519 break;
520
521
522
523 case RESTART:
524 restart();
525 game_state = PLAY0;
526 return;
527
528
529
530 case GAMEOVER:
531 switch (screen_gameover()) {
532 case SCREEN_RUNNING:
533 return;
534 case SCREEN_DONE:
535 game_state = GETNAME;
536 break;
537 case SCREEN_EXIT:
538 game_state = EXIT;
539 break;
540 }
541 break;
542
543
544
545 case GETNAME:
546 switch (screen_getname()) {
547 case SCREEN_RUNNING:
548 return;
549 case SCREEN_DONE:
550 game_state = INIT_GAME;
551 return;
552 case SCREEN_EXIT:
553 game_state = EXIT;
554 break;
555 }
556 break;
557
558
559
560 case EXIT:
561 return;
562
563 }
564 }
565}
566
567
568/*
569 * Initialize the game
570 */
571static void
572init(void)
573{
574 U8 i;
575
576 e_rick_state_clear(0xff);
577
578 game_lives = 6;
579 game_bombs = 6;
580 game_bullets = 6;
581 game_score = 0;
582
583 game_map = sysarg_args_map;
584
585 if (sysarg_args_submap == 0)
586 {
587 game_submap = map_maps[game_map].submap;
588 map_frow = (U8)map_maps[game_map].row;
589 }
590 else
591 {
592 /* dirty hack to determine frow */
593 game_submap = sysarg_args_submap;
594 i = 0;
595 while (i < map_nbr_connect &&
596 (map_connect[i].submap != game_submap ||
597 map_connect[i].dir != RIGHT))
598 {
599 i++;
600 }
601 map_frow = map_connect[i].rowin - 0x10;
602 ent_ents[1].y = 0x10 << 3;
603 }
604
605 ent_ents[1].x = map_maps[game_map].x;
606 ent_ents[1].y = map_maps[game_map].y;
607 ent_ents[1].w = 0x18;
608 ent_ents[1].h = 0x15;
609 ent_ents[1].n = 0x01;
610 ent_ents[1].sprite = 0x01;
611 ent_ents[1].front = false;
612 ent_ents[ENT_ENTSNUM].n = 0xFF;
613
614 map_resetMarks();
615
616 map_init();
617 isave();
618}
619
620
621/*
622 * play0
623 *
624 */
625static void
626play0(void)
627{
628 if (control_test(Control_END)) { /* request to end the game */
629 game_state = GAMEOVER;
630 return;
631 }
632
633 if (control_test(Control_EXIT)) { /* request to exit the game */
634 game_state = EXIT;
635 return;
636 }
637
638 ent_action(); /* run entities */
639 e_them_rndseed++; /* (0270) */
640
641 game_state = PLAY1;
642}
643
644
645/*
646 * play3
647 *
648 */
649static void
650play3(void)
651{
652 draw_clearStatus(); /* clear the status bar */
653 ent_draw(); /* draw all entities onto the buffer */
654 /* sound */
655 draw_drawStatus(); /* draw the status bar onto the buffer*/
656
657 game_rects = &draw_STATUSRECT; /* refresh status bar too */
658 draw_STATUSRECT.next = ent_rects; /* take care to cleanup draw_STATUSRECT->next later! */
659
660 if (!e_rick_state_test(E_RICK_STZOMBIE)) { /* need to scroll ? */
661 if (ent_ents[1].y >= 0xCC) {
662 game_state = SCROLL_UP;
663 return;
664 }
665 if (ent_ents[1].y <= 0x60) {
666 game_state = SCROLL_DOWN;
667 return;
668 }
669 }
670
671 game_state = PLAY0;
672}
673
674
675/*
676 * restart
677 *
678 */
679static void
680restart(void)
681{
682 e_rick_state_clear(E_RICK_STDEAD|E_RICK_STZOMBIE);
683
684 game_bullets = 6;
685 game_bombs = 6;
686
687 ent_ents[1].n = 1;
688
689 irestore();
690 map_init();
691 isave();
692 ent_clprev();
693 draw_map();
694 draw_drawStatus();
695 game_rects = &draw_SCREENRECT;
696}
697
698
699/*
700 * isave (0bbb)
701 *
702 */
703static void
704isave(void)
705{
706 e_rick_save();
707 isave_frow = map_frow;
708}
709
710
711/*
712 * irestore (0bdc)
713 *
714 */
715static void
716irestore(void)
717{
718 e_rick_restore();
719 map_frow = isave_frow;
720}
721
722/* eof */
diff --git a/apps/plugins/xrick/game.h b/apps/plugins/xrick/game.h
new file mode 100644
index 0000000000..025c3bdbe2
--- /dev/null
+++ b/apps/plugins/xrick/game.h
@@ -0,0 +1,73 @@
1/*
2 * xrick/game.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _GAME_H
17#define _GAME_H
18
19#include "xrick/config.h"
20#include "xrick/rects.h"
21#ifdef ENABLE_SOUND
22#include "xrick/data/sounds.h"
23#endif
24
25#include <stddef.h> /* NULL */
26
27#define LEFT 1
28#define RIGHT 0
29
30#define GAME_PERIOD 40
31
32#define GAME_BOMBS_INIT 6
33#define GAME_BULLETS_INIT 6
34
35extern U8 game_lives; /* lives counter */
36extern U8 game_bombs; /* bombs counter */
37extern U8 game_bullets; /* bullets counter */
38
39extern U32 game_score; /* score */
40
41extern U16 game_map; /* current map */
42extern U16 game_submap; /* current submap */
43
44extern U8 game_dir; /* direction (LEFT, RIGHT) */
45extern bool game_chsm; /* change submap request (true, false) */
46
47extern bool game_waitevt; /* wait for events (true, false) */
48extern U8 game_period; /* time between each frame, in millisecond */
49
50extern const rect_t *game_rects; /* rectangles to redraw at each frame */
51
52extern void game_run(void);
53#ifdef ENABLE_SOUND
54extern void game_setmusic(sound_t * sound, S8 loop);
55extern void game_stopmusic(void);
56#endif /* ENABLE_SOUND */
57
58#ifdef ENABLE_CHEATS
59typedef enum
60{
61 Cheat_UNLIMITED_ALL,
62 Cheat_NEVER_DIE,
63 Cheat_EXPOSE
64} cheat_t;
65extern bool game_cheat1; /* infinite lives, bombs and bullets */
66extern bool game_cheat2; /* never die */
67extern bool game_cheat3; /* highlight sprites */
68extern void game_toggleCheat(cheat_t);
69#endif /* ENABLE_CHEATS */
70
71#endif /* ndef _GAME_H */
72
73/* eof */
diff --git a/apps/plugins/xrick/maps.c b/apps/plugins/xrick/maps.c
new file mode 100644
index 0000000000..f85d0b9906
--- /dev/null
+++ b/apps/plugins/xrick/maps.c
@@ -0,0 +1,253 @@
1/*
2 * xrick/maps.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16/*
17 * NOTES
18 *
19 * A map is composed of submaps, which in turn are composed of rows of
20 * 0x20 tiles. map_map contains the tiles for the current portion of the
21 * current submap, i.e. a little bit more than what appear on the screen,
22 * but not the whole submap.
23 *
24 * map_frow is map_map top row within the submap.
25 *
26 * Submaps are stored as arrays of blocks, each block being a 4x4 tile
27 * array. map_submaps[].bnum points to the first block of the array.
28 *
29 * Before a submap can be played, it needs to be expanded from blocks
30 * to map_map.
31 */
32
33#include "xrick/maps.h"
34
35#include "xrick/game.h"
36#include "xrick/debug.h"
37#include "xrick/control.h"
38#include "xrick/ents.h"
39#include "xrick/draw.h"
40#include "xrick/screens.h"
41#include "xrick/e_sbonus.h"
42
43/*
44 * global vars
45 */
46U8 map_map[0x2C][0x20];
47
48size_t map_nbr_maps = 0;
49map_t *map_maps = NULL;
50
51size_t map_nbr_submaps = 0;
52submap_t *map_submaps = NULL;
53
54size_t map_nbr_connect = 0;
55connect_t *map_connect = NULL;
56
57size_t map_nbr_blocks = 0;
58block_t *map_blocks = NULL;
59
60size_t map_nbr_marks = 0;
61mark_t *map_marks = NULL;
62
63size_t map_nbr_bnums = 0;
64U8 *map_bnums = NULL;
65
66size_t map_nbr_eflgc = 0;
67U8 *map_eflg_c = NULL;
68U8 map_eflg[0x100];
69
70U8 map_frow;
71U8 map_tilesBank;
72
73
74/*
75 * prototypes
76 */
77static void map_eflg_expand(U8);
78
79
80/*
81 * Fill in map_map with tile numbers by expanding blocks.
82 *
83 * add map_submaps[].bnum to map_frow to find out where to start from.
84 * We need to /4 map_frow to convert from tile rows to block rows, then
85 * we need to *8 to convert from block rows to block numbers (there
86 * are 8 blocks per block row). This is achieved by *2 then &0xfff8.
87 */
88void
89map_expand(void)
90{
91 U8 i, j, k, l;
92 U8 row, col;
93 U16 pbnum;
94
95 pbnum = map_submaps[game_submap].bnum + ((2 * map_frow) & 0xfff8);
96 row = col = 0;
97
98 for (i = 0; i < 0x0b; i++) { /* 0x0b rows of blocks */
99 for (j = 0; j < 0x08; j++) { /* 0x08 blocks per row */
100 for (k = 0, l = 0; k < 0x04; k++) { /* expand one block */
101 map_map[row][col++] = map_blocks[map_bnums[pbnum]][l++];
102 map_map[row][col++] = map_blocks[map_bnums[pbnum]][l++];
103 map_map[row][col++] = map_blocks[map_bnums[pbnum]][l++];
104 map_map[row][col] = map_blocks[map_bnums[pbnum]][l++];
105 row += 1; col -= 3;
106 }
107 row -= 4; col += 4;
108 pbnum++;
109 }
110 row += 4; col = 0;
111 }
112}
113
114
115/*
116 * Initialize a new submap
117 *
118 * ASM 0cc3
119 */
120void
121map_init(void)
122{
123 /*sys_printf("xrick/map_init: map=%#04x submap=%#04x\n", g_map, game_submap);*/
124#ifdef GFXPC
125 draw_filter = 0xffff;
126 map_tilesBank = 2 + map_submaps[game_submap].page;
127#endif
128#ifdef GFXST
129 map_tilesBank = 1 + map_submaps[game_submap].page;
130#endif
131 map_eflg_expand(map_submaps[game_submap].page << 4);
132 map_expand();
133 ent_reset();
134 ent_actvis(map_frow + MAP_ROW_SCRTOP, map_frow + MAP_ROW_SCRBOT);
135 ent_actvis(map_frow + MAP_ROW_HTTOP, map_frow + MAP_ROW_HTBOT);
136 ent_actvis(map_frow + MAP_ROW_HBTOP, map_frow + MAP_ROW_HBBOT);
137}
138
139
140/*
141 * Expand entity flags for this map
142 *
143 * ASM 1117
144 */
145void
146map_eflg_expand(U8 offs)
147{
148 U8 i, j, k;
149
150 for (i = 0, k = 0; i < 0x10; i++) {
151 j = map_eflg_c[offs + i++];
152 while (j--) map_eflg[k++] = map_eflg_c[offs + i];
153 }
154}
155
156
157/*
158 * Chain (sub)maps
159 *
160 * ASM 0c08
161 * return: true/next submap OK, false/map finished
162 */
163bool
164map_chain(void)
165{
166 U16 c, t;
167
168 game_chsm = false;
169 e_sbonus_counting = false;
170
171 /* find connection */
172 c = map_submaps[game_submap].connect;
173 t = 3;
174
175 IFDEBUG_MAPS(
176 sys_printf("xrick/maps: chain submap=%#04x frow=%#04x .connect=%#04x %s\n",
177 game_submap, map_frow, c,
178 (game_dir == LEFT ? "-> left" : "-> right"));
179 );
180
181 /*
182 * look for the first connector with compatible row number. if none
183 * found, then panic
184 */
185 for (c = map_submaps[game_submap].connect ; ; c++)
186 {
187 if (map_connect[c].dir == 0xff)
188 {
189 sys_error("(map_chain) can not find connector\n");
190 control_set(Control_EXIT);
191 return false;
192 }
193 if (map_connect[c].dir != game_dir)
194 {
195 continue;
196 }
197 t = (ent_ents[1].y >> 3) + map_frow - map_connect[c].rowout;
198 if (t < 3)
199 {
200 break;
201 }
202 }
203
204 /* got it */
205 IFDEBUG_MAPS(
206 sys_printf("xrick/maps: chain frow=%#04x y=%#06x\n",
207 map_frow, ent_ents[1].y);
208 sys_printf("xrick/maps: chain connect=%#04x rowout=%#04x - ",
209 c, map_connect[c].rowout);
210 );
211
212 if (map_connect[c].submap == 0xff)
213 {
214 /* no next submap - request next map */
215 IFDEBUG_MAPS(
216 sys_printf("chain to next map\n");
217 );
218 return false;
219 }
220 else
221 {
222 /* next submap */
223 IFDEBUG_MAPS(
224 sys_printf("chain to submap=%#04x rowin=%#04x\n",
225 map_connect[c].submap, map_connect[c].rowin);
226 );
227 map_frow = map_frow - map_connect[c].rowout + map_connect[c].rowin;
228 game_submap = map_connect[c].submap;
229 IFDEBUG_MAPS(
230 sys_printf("xrick/maps: chain frow=%#04x\n",
231 map_frow);
232 );
233 return true;
234 }
235}
236
237
238/*
239 * Reset all marks, i.e. make them all active again.
240 *
241 * ASM 0025
242 *
243 */
244void
245map_resetMarks(void)
246{
247 U16 i;
248 for (i = 0; i < map_nbr_marks; i++)
249 map_marks[i].ent &= ~MAP_MARK_NACT;
250}
251
252
253/* eof */
diff --git a/apps/plugins/xrick/maps.h b/apps/plugins/xrick/maps.h
new file mode 100644
index 0000000000..716c6589ad
--- /dev/null
+++ b/apps/plugins/xrick/maps.h
@@ -0,0 +1,159 @@
1/*
2 * xrick/maps.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _MAPS_H
17#define _MAPS_H
18
19#include "xrick/system/basic_types.h"
20#include "xrick/system/system.h"
21#ifdef ENABLE_SOUND
22#include "xrick/data/sounds.h"
23#endif
24
25#include <stddef.h> /* size_t */
26
27/*
28 * map row definitions, for three zones : hidden top, screen, hidden bottom
29 * the three zones compose map_map, which contains the definition of the
30 * current portion of the submap.
31 */
32#define MAP_ROW_HTTOP 0x00
33#define MAP_ROW_HTBOT 0x07
34#define MAP_ROW_SCRTOP 0x08
35#define MAP_ROW_SCRBOT 0x1F
36#define MAP_ROW_HBTOP 0x20
37#define MAP_ROW_HBBOT 0x27
38
39extern U8 map_map[0x2c][0x20];
40
41/*
42 * main maps
43 */
44typedef struct {
45 U16 x, y; /* initial position for rick */
46 U16 row; /* initial map_map top row within the submap */
47 U16 submap; /* initial submap */
48#ifdef ENABLE_SOUND
49 sound_t * tune; /* map tune */
50#endif
51} map_t;
52
53extern size_t map_nbr_maps;
54extern map_t *map_maps;
55
56/*
57 * sub maps
58 */
59typedef struct {
60 U16 page; /* tiles page */
61 U16 bnum; /* first block number */
62 U16 connect; /* first connection */
63 U16 mark; /* first entity mark */
64} submap_t;
65
66extern size_t map_nbr_submaps;
67extern submap_t *map_submaps;
68
69/*
70 * connections
71 */
72typedef struct {
73 U8 dir;
74 U8 rowout;
75 U8 submap;
76 U8 rowin;
77} connect_t;
78
79extern size_t map_nbr_connect;
80extern connect_t *map_connect;
81
82/*
83 * blocks - one block is 4 by 4 tiles.
84 */
85typedef U8 block_t[0x10];
86
87extern size_t map_nbr_blocks;
88extern block_t *map_blocks;
89
90/*
91 * flags for map_marks[].ent ("yes" when set)
92 *
93 * MAP_MARK_NACT: this mark is not active anymore.
94 */
95#define MAP_MARK_NACT (0x80)
96
97/*
98 * mark structure
99 */
100typedef struct {
101 U8 row;
102 U8 ent;
103 U8 flags;
104 U8 xy; /* bits XXXX XYYY (from b03) with X->x, Y->y */
105 U8 lt; /* bits XXXX XNNN (from b04) with X->trig_x, NNN->lat & trig_y */
106} mark_t;
107
108extern size_t map_nbr_marks;
109extern mark_t *map_marks;
110
111/*
112 * block numbers, i.e. array of rows of 8 blocks
113 */
114extern size_t map_nbr_bnums;
115extern U8 *map_bnums;
116
117/*
118 * flags for map_eflg[map_map[row][col]] ("yes" when set)
119 *
120 * MAP_EFLG_VERT: vertical move only (usually on top of _CLIMB).
121 * MAP_EFLG_SOLID: solid block, can't go through.
122 * MAP_EFLG_SPAD: super pad. can't go through, but sends entities to the sky.
123 * MAP_EFLG_WAYUP: solid block, can't go through except when going up.
124 * MAP_EFLG_FGND: foreground (hides entities).
125 * MAP_EFLG_LETHAL: lethal (kill entities).
126 * MAP_EFLG_CLIMB: entities can climb here.
127 * MAP_EFLG_01:
128 */
129#define MAP_EFLG_VERT (0x80)
130#define MAP_EFLG_SOLID (0x40)
131#define MAP_EFLG_SPAD (0x20)
132#define MAP_EFLG_WAYUP (0x10)
133#define MAP_EFLG_FGND (0x08)
134#define MAP_EFLG_LETHAL (0x04)
135#define MAP_EFLG_CLIMB (0x02)
136#define MAP_EFLG_01 (0x01)
137
138extern size_t map_nbr_eflgc;
139extern U8 *map_eflg_c; /* compressed */
140extern U8 map_eflg[0x100]; /* current */
141
142/*
143 * map_map top row within the submap
144 */
145extern U8 map_frow;
146
147/*
148 * tiles offset
149 */
150extern U8 map_tilesBank;
151
152extern void map_expand(void);
153extern void map_init(void);
154extern bool map_chain(void);
155extern void map_resetMarks(void);
156
157#endif /* ndef _MAPS_H */
158
159/* eof */
diff --git a/apps/plugins/xrick/rects.c b/apps/plugins/xrick/rects.c
new file mode 100644
index 0000000000..9324426060
--- /dev/null
+++ b/apps/plugins/xrick/rects.c
@@ -0,0 +1,57 @@
1/*
2 * xrick/rects.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/rects.h"
17#include "xrick/system/system.h"
18
19/*
20 * Free a list of rectangles and set the pointer to NULL.
21 *
22 * p: rectangle list CHANGED to NULL
23 */
24void
25rects_free(rect_t *r)
26{
27 while (r)
28 {
29 rect_t * next = r->next;
30 sysmem_pop(r);
31 r = next;
32 }
33}
34
35
36/*
37 * Add a rectangle to a list of rectangles
38 */
39rect_t *
40rects_new(U16 x, U16 y, U16 width, U16 height, rect_t *next)
41{
42 rect_t *r;
43
44 r = sysmem_push(sizeof(*r));
45 if (!r)
46 {
47 return NULL;
48 }
49 r->x = x;
50 r->y = y;
51 r->width = width;
52 r->height = height;
53 r->next = next;
54 return r;
55}
56
57/* eof */
diff --git a/apps/plugins/xrick/rects.h b/apps/plugins/xrick/rects.h
new file mode 100644
index 0000000000..ed75f609aa
--- /dev/null
+++ b/apps/plugins/xrick/rects.h
@@ -0,0 +1,32 @@
1/*
2 * xrick/rects.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _RECTS_H
17#define _RECTS_H
18
19#include "xrick/system/basic_types.h"
20
21typedef struct rect_s {
22 U16 x, y;
23 U16 width, height;
24 struct rect_s *next;
25} rect_t;
26
27extern void rects_free(rect_t *);
28extern rect_t *rects_new(U16, U16, U16, U16, rect_t *);
29
30#endif /* ndef _RECTS_H */
31
32/* eof */
diff --git a/apps/plugins/xrick/res_magic.c b/apps/plugins/xrick/res_magic.c
new file mode 100644
index 0000000000..c3365bc816
--- /dev/null
+++ b/apps/plugins/xrick/res_magic.c
@@ -0,0 +1,18 @@
1/*
2 * xrick/res_magic.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/resources.h"
15
16const U8 resource_magic[4] = { 0x52, 0x49, 0x43, 0x4B }; /* 'R','I','C','K' */
17
18/* eof */
diff --git a/apps/plugins/xrick/resources.c b/apps/plugins/xrick/resources.c
new file mode 100644
index 0000000000..d7b49e8f73
--- /dev/null
+++ b/apps/plugins/xrick/resources.c
@@ -0,0 +1,1297 @@
1/*
2 * xrick/resources.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/resources.h"
15
16#include "xrick/draw.h"
17#include "xrick/ents.h"
18#include "xrick/maps.h"
19#include "xrick/util.h"
20#include "xrick/data/sprites.h"
21#include "xrick/data/tiles.h"
22#include "xrick/data/pics.h"
23#include "xrick/system/basic_funcs.h"
24
25#include "xrick/system/miniz_config.h"
26#include "miniz/miniz.c"
27
28/*
29 * prototypes
30 */
31static bool readFile(const unsigned id);
32static bool checkCrc32(const unsigned id);
33static bool readHeader(file_t fp, const unsigned id);
34static bool loadString(file_t fp, char ** str, const char terminator);
35static void unloadString(char ** buffer);
36static bool loadResourceFilelist(file_t fp);
37static void unloadResourceFilelist(void);
38static bool loadResourceEntdata(file_t fp);
39static void unloadResourceEntdata(void);
40static bool loadRawData(file_t fp, void ** buffer, const size_t size, size_t * count);
41static void unloadRawData(void ** buffer, size_t * count);
42static bool loadResourceMaps(file_t fp);
43static void unloadResourceMaps(void);
44static bool loadResourceSubmaps(file_t fp);
45static void unloadResourceSubmaps(void);
46static bool loadResourceImapsteps(file_t fp);
47static void unloadResourceImapsteps(void);
48static bool loadResourceImaptext(file_t fp);
49static void unloadResourceImaptext(void);
50static bool loadResourceHighScores(file_t fp);
51static void unloadResourceHighScores(void);
52static bool loadResourceSpritesData(file_t fp);
53static void unloadResourceSpritesData(void);
54static bool loadResourceTilesData(file_t fp);
55static void unloadResourceTilesData(void);
56static bool loadImage(file_t fp, img_t ** image);
57static void unloadImage(img_t ** image);
58#ifdef GFXST
59static bool loadPicture(file_t fp, pic_t ** picture);
60static void unloadPicture(pic_t ** picture);
61#endif /* GFXST */
62#ifdef ENABLE_SOUND
63static bool fromResourceIdToSound(const unsigned id, sound_t *** sound);
64static bool loadSound(const unsigned id);
65static void unloadSound(const unsigned id);
66#endif /* ENABLE_SOUND */
67
68/*
69 * local vars
70 */
71static char * resourceFiles[Resource_MAX_COUNT] =
72{
73 BOOTSTRAP_RESOURCE_NAME,
74 /* the rest initialised to NULL by default */
75};
76
77/*
78 * load 16b length + not-terminated string
79 */
80static bool loadString(file_t fp, char ** buffer, const char terminator)
81{
82 size_t length;
83 U16 u16Temp;
84 char * bufferTemp;
85
86 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
87 {
88 return false;
89 }
90 length = letoh16(u16Temp);
91
92 bufferTemp = sysmem_push(length + 1);
93 *buffer = bufferTemp;
94 if (!bufferTemp)
95 {
96 return false;
97 }
98
99 if (length)
100 {
101 if (sysfile_read(fp, bufferTemp, length, 1) != 1)
102 {
103 return false;
104 }
105 }
106
107 bufferTemp[length] = terminator;
108
109 return true;
110}
111
112/*
113 *
114 */
115static void unloadString(char ** buffer)
116{
117 sysmem_pop(*buffer);
118 *buffer = NULL;
119}
120
121/*
122 *
123 */
124static bool loadResourceFilelist(file_t fp)
125{
126 unsigned id;
127
128 for (id = Resource_PALETTE; id < Resource_MAX_COUNT; ++id)
129 {
130 if (!loadString(fp, &(resourceFiles[id]), 0x00))
131 {
132 return false;
133 }
134 }
135 return true;
136}
137
138/*
139 *
140 */
141static void unloadResourceFilelist()
142{
143 unsigned id;
144
145 for (id = Resource_MAX_COUNT - 1; id >= Resource_PALETTE; --id)
146 {
147 unloadString(&(resourceFiles[id]));
148 }
149}
150
151/*
152 *
153 */
154static bool loadResourceEntdata(file_t fp)
155{
156 size_t i;
157 U16 u16Temp;
158 resource_entdata_t dataTemp;
159
160 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
161 {
162 return false;
163 }
164 ent_nbr_entdata = letoh16(u16Temp);
165
166 ent_entdata = sysmem_push(ent_nbr_entdata * sizeof(*ent_entdata));
167 if (!ent_entdata)
168 {
169 return false;
170 }
171
172 for (i = 0; i < ent_nbr_entdata; ++i)
173 {
174 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
175 {
176 return false;
177 }
178 ent_entdata[i].w = dataTemp.w;
179 ent_entdata[i].h = dataTemp.h;
180 memcpy(&u16Temp, dataTemp.spr, sizeof(U16));
181 ent_entdata[i].spr = letoh16(u16Temp);
182 memcpy(&u16Temp, dataTemp.sni, sizeof(U16));
183 ent_entdata[i].sni = letoh16(u16Temp);
184 ent_entdata[i].trig_w = dataTemp.trig_w;
185 ent_entdata[i].trig_h = dataTemp.trig_h;
186 ent_entdata[i].snd = dataTemp.snd;
187 }
188 return true;
189}
190
191/*
192 *
193 */
194static void unloadResourceEntdata()
195{
196 sysmem_pop(ent_entdata);
197 ent_entdata = NULL;
198 ent_nbr_entdata = 0;
199}
200
201/*
202 *
203 */
204static bool loadRawData(file_t fp, void ** buffer, const size_t size, size_t * count)
205{
206 U16 u16Temp;
207 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
208 {
209 return false;
210 }
211 *count = letoh16(u16Temp);
212
213 *buffer = sysmem_push((*count) * size);
214 if (!(*buffer))
215 {
216 return false;
217 }
218
219 if (sysfile_read(fp, *buffer, size, *count) != (int)(*count))
220 {
221 return false;
222 }
223 return true;
224}
225
226/*
227 *
228 */
229static void unloadRawData(void ** buffer, size_t * count)
230{
231 sysmem_pop(*buffer);
232 *buffer = NULL;
233 *count = 0;
234}
235
236/*
237 *
238 */
239static bool loadResourceMaps(file_t fp)
240{
241 size_t i;
242 U16 u16Temp;
243 resource_map_t dataTemp;
244
245 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
246 {
247 return false;
248 }
249 map_nbr_maps = letoh16(u16Temp);
250
251 map_maps = sysmem_push(map_nbr_maps * sizeof(*map_maps));
252 if (!map_maps)
253 {
254 return false;
255 }
256
257 for (i = 0; i < map_nbr_maps; ++i)
258 {
259#ifdef ENABLE_SOUND
260 sound_t **soundTemp;
261#endif
262 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
263 {
264 return false;
265 }
266 memcpy(&u16Temp, dataTemp.x, sizeof(U16));
267 map_maps[i].x = letoh16(u16Temp);
268 memcpy(&u16Temp, dataTemp.y, sizeof(U16));
269 map_maps[i].y = letoh16(u16Temp);
270 memcpy(&u16Temp, dataTemp.row, sizeof(U16));
271 map_maps[i].row = letoh16(u16Temp);
272 memcpy(&u16Temp, dataTemp.submap, sizeof(U16));
273 map_maps[i].submap = letoh16(u16Temp);
274#ifdef ENABLE_SOUND
275 memcpy(&u16Temp, dataTemp.tuneId, sizeof(U16));
276 if (!fromResourceIdToSound(letoh16(u16Temp), &soundTemp))
277 {
278 return false;
279 }
280 map_maps[i].tune = *soundTemp;
281#endif /* ENABLE_SOUND */
282 }
283 return true;
284}
285
286/*
287 *
288 */
289static void unloadResourceMaps()
290{
291 sysmem_pop(map_maps);
292 map_maps = NULL;
293 map_nbr_maps = 0;
294}
295
296/*
297 *
298 */
299static bool loadResourceSubmaps(file_t fp)
300{
301 size_t i;
302 U16 u16Temp;
303 resource_submap_t dataTemp;
304
305 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
306 {
307 return false;
308 }
309 map_nbr_submaps = letoh16(u16Temp);
310
311 map_submaps = sysmem_push(map_nbr_submaps * sizeof(*map_submaps));
312 if (!map_submaps)
313 {
314 return false;
315 }
316
317 for (i = 0; i < map_nbr_submaps; ++i)
318 {
319 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
320 {
321 return false;
322 }
323 memcpy(&u16Temp, dataTemp.page, sizeof(U16));
324 map_submaps[i].page = letoh16(u16Temp);
325 memcpy(&u16Temp, dataTemp.bnum, sizeof(U16));
326 map_submaps[i].bnum = letoh16(u16Temp);
327 memcpy(&u16Temp, dataTemp.connect, sizeof(U16));
328 map_submaps[i].connect = letoh16(u16Temp);
329 memcpy(&u16Temp, dataTemp.mark, sizeof(U16));
330 map_submaps[i].mark = letoh16(u16Temp);
331 }
332 return true;
333}
334
335/*
336 *
337 */
338static void unloadResourceSubmaps()
339{
340 sysmem_pop(map_submaps);
341 map_submaps = NULL;
342 map_nbr_submaps = 0;
343}
344
345/*
346 *
347 */
348static bool loadResourceImapsteps(file_t fp)
349{
350 size_t i;
351 U16 u16Temp;
352 resource_imapsteps_t dataTemp;
353
354 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
355 {
356 return false;
357 }
358 screen_nbr_imapstesps = letoh16(u16Temp);
359
360 screen_imapsteps = sysmem_push(screen_nbr_imapstesps * sizeof(*screen_imapsteps));
361 if (!screen_imapsteps)
362 {
363 return false;
364 }
365
366 for (i = 0; i < screen_nbr_imapstesps; ++i)
367 {
368 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
369 {
370 return false;
371 }
372 memcpy(&u16Temp, dataTemp.count, sizeof(U16));
373 screen_imapsteps[i].count = letoh16(u16Temp);
374 memcpy(&u16Temp, dataTemp.dx, sizeof(U16));
375 screen_imapsteps[i].dx = letoh16(u16Temp);
376 memcpy(&u16Temp, dataTemp.dy, sizeof(U16));
377 screen_imapsteps[i].dy = letoh16(u16Temp);
378 memcpy(&u16Temp, dataTemp.base, sizeof(U16));
379 screen_imapsteps[i].base = letoh16(u16Temp);
380 }
381 return true;
382}
383
384/*
385 *
386 */
387static void unloadResourceImapsteps()
388{
389 sysmem_pop(screen_imapsteps);
390 screen_imapsteps = NULL;
391 screen_nbr_imapstesps = 0;
392}
393
394/*
395 *
396 */
397static bool loadResourceImaptext(file_t fp)
398{
399 size_t i;
400 U16 u16Temp;
401
402 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
403 {
404 return false;
405 }
406 screen_nbr_imaptext = letoh16(u16Temp);
407
408 screen_imaptext = sysmem_push(screen_nbr_imaptext * sizeof(*screen_imaptext));
409 if (!screen_imapsteps)
410 {
411 return false;
412 }
413
414 for (i = 0; i < screen_nbr_imaptext; ++i)
415 {
416 if (!loadString(fp, (char **)(&(screen_imaptext[i])), 0xFE))
417 {
418 return false;
419 }
420 }
421 return true;
422}
423
424/*
425 *
426 */
427static void unloadResourceImaptext()
428{
429 int i;
430
431 for (i = screen_nbr_imaptext - 1; i >= 0; --i)
432 {
433 unloadString((char **)(&(screen_imaptext[i])));
434 }
435
436 sysmem_pop(screen_imaptext);
437 screen_imaptext = NULL;
438 screen_nbr_imaptext = 0;
439}
440
441/*
442 *
443 */
444static bool loadResourceHighScores(file_t fp)
445{
446 size_t i;
447 U16 u16Temp;
448 U32 u32Temp;
449 resource_hiscore_t dataTemp;
450
451 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
452 {
453 return false;
454 }
455 screen_nbr_hiscores = letoh16(u16Temp);
456
457 screen_highScores = sysmem_push(screen_nbr_hiscores * sizeof(*screen_highScores));
458 if (!screen_highScores)
459 {
460 return false;
461 }
462
463 for (i = 0; i < screen_nbr_hiscores; ++i)
464 {
465 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
466 {
467 return false;
468 }
469 memcpy(&u32Temp, dataTemp.score, sizeof(U32));
470 screen_highScores[i].score = letoh32(u32Temp);
471 memcpy(screen_highScores[i].name, dataTemp.name, HISCORE_NAME_SIZE);
472 }
473 return true;
474}
475
476/*
477 *
478 */
479static void unloadResourceHighScores()
480{
481 sysmem_pop(screen_highScores);
482 screen_highScores = NULL;
483 screen_nbr_hiscores = 0;
484}
485
486/*
487 *
488 */
489static bool loadResourceSpritesData(file_t fp)
490{
491 size_t i, j;
492 U16 u16Temp;
493
494 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
495 {
496 return false;
497 }
498 sprites_nbr_sprites = letoh16(u16Temp);
499
500 sprites_data = sysmem_push(sprites_nbr_sprites * sizeof(*sprites_data));
501 if (!sprites_data)
502 {
503 return false;
504 }
505
506#ifdef GFXST
507 for (i = 0; i < sprites_nbr_sprites; ++i)
508 {
509 for (j = 0; j < SPRITES_NBR_DATA; ++j)
510 {
511 U32 u32Temp;
512 if (sysfile_read(fp, &u32Temp, sizeof(u32Temp), 1) != 1)
513 {
514 return false;
515 }
516 sprites_data[i][j] = letoh32(u32Temp);
517 }
518 }
519#endif /* GFXST */
520
521#ifdef GFXPC
522 for (i = 0; i < sprites_nbr_sprites; ++i)
523 {
524 for (j = 0; j < SPRITES_NBR_COLS; ++j)
525 {
526 size_t k;
527 for (k = 0; k < SPRITES_NBR_ROWS; ++k)
528 {
529 resource_spriteX_t dataTemp;
530 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
531 {
532 return false;
533 }
534 memcpy(&u16Temp, dataTemp.mask, sizeof(U16));
535 sprites_data[i][j][k].mask = letoh16(u16Temp);
536 memcpy(&u16Temp, dataTemp.pict, sizeof(U16));
537 sprites_data[i][j][k].pict = letoh16(u16Temp);
538 }
539 }
540 }
541#endif /* GFXPC */
542
543 return true;
544}
545
546/*
547 *
548 */
549static void unloadResourceSpritesData()
550{
551 sysmem_pop(sprites_data);
552 sprites_data = NULL;
553 sprites_nbr_sprites = 0;
554}
555
556/*
557 *
558 */
559static bool loadResourceTilesData(file_t fp)
560{
561 size_t i, j, k;
562 U16 u16Temp;
563
564 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
565 {
566 return false;
567 }
568 tiles_nbr_banks = letoh16(u16Temp);
569
570 tiles_data = sysmem_push(tiles_nbr_banks * TILES_NBR_TILES * sizeof(*tiles_data));
571 if (!tiles_data)
572 {
573 return false;
574 }
575
576 for (i = 0; i < tiles_nbr_banks ; ++i)
577 {
578 for (j = 0; j < TILES_NBR_TILES; ++j)
579 {
580 for (k = 0; k < TILES_NBR_LINES ; ++k)
581 {
582#ifdef GFXPC
583 if (sysfile_read(fp, &u16Temp, sizeof(u16Temp), 1) != 1)
584 {
585 return false;
586 }
587 tiles_data[i * TILES_NBR_TILES + j][k] = letoh16(u16Temp);
588#endif /* GFXPC */
589#ifdef GFXST
590 U32 u32Temp;
591 if (sysfile_read(fp, &u32Temp, sizeof(u32Temp), 1) != 1)
592 {
593 return false;
594 }
595 tiles_data[i * TILES_NBR_TILES + j][k] = letoh32(u32Temp);
596#endif /* GFXST */
597 }
598 }
599 }
600 return true;
601}
602
603/*
604 *
605 */
606static void unloadResourceTilesData()
607{
608 sysmem_pop(tiles_data);
609 tiles_data = NULL;
610 tiles_nbr_banks = 0;
611}
612
613/*
614 *
615 */
616static bool loadImage(file_t fp, img_t ** image)
617{
618 U16 u16Temp;
619 size_t pixelCount, colorCount;
620 resource_pic_t dataTemp;
621 img_t * imgTemp;
622 void * vp;
623 bool success;
624
625 imgTemp = sysmem_push(sizeof(*imgTemp));
626 *image = imgTemp;
627 if (!imgTemp)
628 {
629 return false;
630 }
631
632 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
633 {
634 return false;
635 }
636 memcpy(&u16Temp, dataTemp.width, sizeof(U16));
637 imgTemp->width = letoh16(u16Temp);
638 memcpy(&u16Temp, dataTemp.height, sizeof(U16));
639 imgTemp->height = letoh16(u16Temp);
640 memcpy(&u16Temp, dataTemp.xPos, sizeof(U16));
641 imgTemp->xPos = letoh16(u16Temp);
642 memcpy(&u16Temp, dataTemp.yPos, sizeof(U16));
643 imgTemp->yPos = letoh16(u16Temp);
644
645 vp = imgTemp->colors;
646 success = loadRawData(fp, &vp, sizeof(*imgTemp->colors), &colorCount);
647 imgTemp->ncolors = colorCount;
648 imgTemp->colors = vp;
649 if (!success)
650 {
651 return false;
652 }
653
654 pixelCount = (imgTemp->width * imgTemp->height); /*we use 8b per pixel*/
655
656 imgTemp->pixels = sysmem_push(pixelCount * sizeof(U8));
657 if (!imgTemp->pixels)
658 {
659 return false;
660 }
661
662 if (sysfile_read(fp, imgTemp->pixels, sizeof(U8), pixelCount) != (int)pixelCount)
663 {
664 return false;
665 }
666 return true;
667}
668
669/*
670 *
671 */
672static void unloadImage(img_t ** image)
673{
674 if (*image)
675 {
676 sysmem_pop((*image)->pixels);
677 sysmem_pop((*image)->colors);
678 }
679 sysmem_pop(*image);
680 *image = NULL;
681}
682
683/*
684 *
685 */
686#ifdef GFXST
687static bool loadPicture(file_t fp, pic_t ** picture)
688{
689 U16 u16Temp;
690 size_t i, pixelWords32b;
691 resource_pic_t dataTemp;
692 pic_t * picTemp;
693
694 picTemp = sysmem_push(sizeof(*picTemp));
695 *picture = picTemp;
696 if (!picTemp)
697 {
698 return false;
699 }
700
701 if (sysfile_read(fp, &dataTemp, sizeof(dataTemp), 1) != 1)
702 {
703 return false;
704 }
705 memcpy(&u16Temp, dataTemp.width, sizeof(U16));
706 picTemp->width = letoh16(u16Temp);
707 memcpy(&u16Temp, dataTemp.height, sizeof(U16));
708 picTemp->height = letoh16(u16Temp);
709 memcpy(&u16Temp, dataTemp.xPos, sizeof(U16));
710 picTemp->xPos = letoh16(u16Temp);
711 memcpy(&u16Temp, dataTemp.yPos, sizeof(U16));
712 picTemp->yPos = letoh16(u16Temp);
713
714 pixelWords32b = (picTemp->width * picTemp->height) / 8; /*we use 4b per pixel*/
715
716 picTemp->pixels = sysmem_push(pixelWords32b * sizeof(U32));
717 if (!picTemp->pixels)
718 {
719 return false;
720 }
721
722 for (i = 0; i < pixelWords32b; ++i)
723 {
724 U32 u32Temp;
725 if (sysfile_read(fp, &u32Temp, sizeof(u32Temp), 1) != 1)
726 {
727 return false;
728 }
729 picTemp->pixels[i] = letoh32(u32Temp);
730 }
731 return true;
732}
733
734/*
735 *
736 */
737static void unloadPicture(pic_t ** picture)
738{
739 if (*picture)
740 {
741 sysmem_pop((*picture)->pixels);
742 }
743 sysmem_pop(*picture);
744 *picture = NULL;
745}
746#endif /* GFXST */
747
748#ifdef ENABLE_SOUND
749
750/*
751 *
752 */
753static bool fromResourceIdToSound(const unsigned id, sound_t *** sound)
754{
755 switch (id)
756 {
757 case Resource_SOUNDBOMBSHHT: *sound = &soundBombshht; return true;
758 case Resource_SOUNDBONUS: *sound = &soundBonus; return true;
759 case Resource_SOUNDBOX: *sound = &soundBox; return true;
760 case Resource_SOUNDBULLET: *sound = &soundBullet; return true;
761 case Resource_SOUNDCRAWL: *sound = &soundCrawl; return true;
762 case Resource_SOUNDDIE: *sound = &soundDie; return true;
763 case Resource_SOUNDENTITY0: *sound = &(soundEntity[0]); return true;
764 case Resource_SOUNDENTITY1: *sound = &(soundEntity[1]); return true;
765 case Resource_SOUNDENTITY2: *sound = &(soundEntity[2]); return true;
766 case Resource_SOUNDENTITY3: *sound = &(soundEntity[3]); return true;
767 case Resource_SOUNDENTITY4: *sound = &(soundEntity[4]); return true;
768 case Resource_SOUNDENTITY5: *sound = &(soundEntity[5]); return true;
769 case Resource_SOUNDENTITY6: *sound = &(soundEntity[6]); return true;
770 case Resource_SOUNDENTITY7: *sound = &(soundEntity[7]); return true;
771 case Resource_SOUNDENTITY8: *sound = &(soundEntity[8]); return true;
772 case Resource_SOUNDEXPLODE: *sound = &soundExplode; return true;
773 case Resource_SOUNDGAMEOVER: *sound = &soundGameover; return true;
774 case Resource_SOUNDJUMP: *sound = &soundJump; return true;
775 case Resource_SOUNDPAD: *sound = &soundPad; return true;
776 case Resource_SOUNDSBONUS1: *sound = &soundSbonus1; return true;
777 case Resource_SOUNDSBONUS2: *sound = &soundSbonus2; return true;
778 case Resource_SOUNDSTICK: *sound = &soundStick; return true;
779 case Resource_SOUNDTUNE0: *sound = &soundTune0; return true;
780 case Resource_SOUNDTUNE1: *sound = &soundTune1; return true;
781 case Resource_SOUNDTUNE2: *sound = &soundTune2; return true;
782 case Resource_SOUNDTUNE3: *sound = &soundTune3; return true;
783 case Resource_SOUNDTUNE4: *sound = &soundTune4; return true;
784 case Resource_SOUNDTUNE5: *sound = &soundTune5; return true;
785 case Resource_SOUNDWALK: *sound = &soundWalk; return true;
786 default:
787 {
788 sys_error("(resources) no associated sound found for ID %d", id);
789 return false;
790 }
791 }
792}
793
794/*
795 *
796 */
797static bool loadSound(const unsigned id)
798{
799 sound_t ** sound;
800 file_t fp;
801 wave_header_t header;
802 U16 u16Temp;
803 U32 u32Temp;
804 int bytesRead;
805 bool isHeaderValid;
806
807 if (!fromResourceIdToSound(id, &sound))
808 {
809 return false;
810 }
811
812 *sound = sysmem_push(sizeof(**sound));
813 if (!*sound)
814 {
815 return false;
816 }
817
818 (*sound)->buf = NULL;
819 (*sound)->dispose = true; /* sounds are "fire and forget" by default */
820
821 (*sound)->name = u_strdup(resourceFiles[id]);
822 if (!(*sound)->name)
823 {
824 return false;
825 }
826
827 fp = sysfile_open(resourceFiles[id]);
828 if (!fp)
829 {
830 sys_error("(resources) unable to open \"%s\"", resourceFiles[id]);
831 return false;
832 }
833
834 bytesRead = sysfile_read(fp, &header, sizeof(header), 1);
835 sysfile_close(fp);
836 if (bytesRead != 1)
837 {
838 sys_error("(resources) unable to read WAVE header from \"%s\"", resourceFiles[id]);
839 return false;
840 }
841
842 isHeaderValid = false;
843 for (;;)
844 {
845 if (memcmp(header.riffChunkId, "RIFF", 4) ||
846 memcmp(header.riffType, "WAVE", 4) ||
847 memcmp(header.formatChunkId, "fmt ", 4) ||
848 memcmp(header.dataChunkId, "data", 4))
849 {
850 break;
851 }
852 memcpy(&u16Temp, header.audioFormat, sizeof(u16Temp));
853 if (letoh16(u16Temp) != Wave_AUDIO_FORMAT)
854 {
855 break;
856 }
857 memcpy(&u16Temp, header.channelCount, sizeof(u16Temp));
858 if (letoh16(u16Temp) != Wave_CHANNEL_COUNT)
859 {
860 break;
861 }
862 memcpy(&u32Temp, header.sampleRate, sizeof(u32Temp));
863 if (letoh32(u32Temp) != Wave_SAMPLE_RATE)
864 {
865 isHeaderValid = false;
866 break;
867 }
868 memcpy(&u16Temp, header.bitsPerSample, sizeof(u16Temp));
869 if (letoh16(u16Temp) != Wave_BITS_PER_SAMPLE)
870 {
871 isHeaderValid = false;
872 break;
873 }
874
875 memcpy(&u32Temp, header.dataChunkSize, sizeof(u32Temp));
876 (*sound)->len = letoh32(u32Temp);
877
878 isHeaderValid = true;
879 break;
880 }
881 if (!isHeaderValid)
882 {
883 sys_error("(resources) incompatible WAVE header for \"%s\"", resourceFiles[id]);
884 return false;
885 }
886 return true;
887}
888
889/*
890 *
891 */
892static void unloadSound(const unsigned id)
893{
894 sound_t ** sound;
895
896 if (!fromResourceIdToSound(id, &sound))
897 {
898 return;
899 }
900
901 if (!*sound)
902 {
903 return;
904 }
905
906 sysmem_pop((*sound)->name);
907 sysmem_pop(*sound);
908 *sound = NULL;
909}
910#endif /* ENABLE_SOUND */
911
912
913/*
914 *
915 */
916static bool readHeader(file_t fp, const unsigned id)
917{
918 resource_header_t header;
919 U16 u16Temp;
920
921 if (sysfile_read(fp, &header, sizeof(header), 1) != 1)
922 {
923 sys_error("(resources) unable to read header from \"%s\"", resourceFiles[id]);
924 return false;
925 }
926
927 if (memcmp(header.magic, resource_magic, sizeof(header.magic)) != 0)
928 {
929 sys_error("(resources) wrong header for \"%s\"", resourceFiles[id]);
930 return false;
931 }
932
933 memcpy(&u16Temp, header.version, sizeof(u16Temp));
934 u16Temp = htole16(u16Temp);
935 if (u16Temp != DATA_VERSION)
936 {
937 sys_error("(resources) incompatible version for \"%s\"", resourceFiles[id]);
938 return false;
939 }
940
941 memcpy(&u16Temp, header.resourceId, sizeof(u16Temp));
942 u16Temp = htole16(u16Temp);
943 if (u16Temp != id)
944 {
945 sys_error("(resources) mismatching ID for \"%s\"", resourceFiles[id]);
946 return false;
947 }
948 return true;
949}
950
951/*
952 *
953 */
954static bool checkCrc32(const unsigned id)
955{
956 int bytesRead;
957 U8 tempBuffer[1024];
958 U32 expectedCrc32, calculatedCrc32 = MZ_CRC32_INIT;
959
960 file_t fp = sysfile_open(resourceFiles[id]);
961 if (fp == NULL)
962 {
963 sys_error("(resources) unable to open \"%s\"", resourceFiles[id]);
964 return false;
965 }
966
967 bytesRead = sysfile_read(fp, tempBuffer, sizeof(U32), 1); /* prepare beginning of buffer for the following loop */
968 if (bytesRead != 1)
969 {
970 sys_error("(resources) not enough data for \"%s\"", resourceFiles[id]);
971 sysfile_close(fp);
972 return false;
973 }
974 do
975 {
976 bytesRead = sysfile_read(fp, tempBuffer + sizeof(U32), sizeof(U8), sizeof(tempBuffer) - sizeof(U32));
977
978 calculatedCrc32 = mz_crc32(calculatedCrc32, tempBuffer, bytesRead);
979
980 memcpy(tempBuffer, tempBuffer + bytesRead, sizeof(U32));
981 } while (bytesRead == sizeof(tempBuffer) - sizeof(U32));
982
983 sysfile_close(fp);
984
985 memcpy(&expectedCrc32, tempBuffer, sizeof(U32));
986 expectedCrc32 = letoh32(expectedCrc32);
987 if (expectedCrc32 != calculatedCrc32)
988 {
989 sys_error("(resources) crc check failed for \"%s\"", resourceFiles[id]);
990 return false;
991 }
992 return true;
993}
994
995/*
996 *
997 */
998static bool readFile(const unsigned id)
999{
1000 bool success;
1001 file_t fp;
1002 void * vp;
1003
1004 switch (id)
1005 {
1006#ifndef GFXST
1007 case Resource_PICHAF: /* fallthrough */
1008 case Resource_PICCONGRATS: /* fallthrough */
1009 case Resource_PICSPLASH: return true;
1010#endif /* ndef GFXST */
1011#ifndef GFXPC
1012 case Resource_IMAINHOFT: /* fallthrough */
1013 case Resource_IMAINRDT: /* fallthrough */
1014 case Resource_IMAINCDC: /* fallthrough */
1015 case Resource_SCREENCONGRATS: return true;
1016#endif /* ndef GFXPC */
1017 default: break;
1018 }
1019
1020 if (resourceFiles[id] == NULL)
1021 {
1022 sys_error("(resources) resource ID %d not available", id);
1023 return false;
1024 }
1025
1026 if (!checkCrc32(id))
1027 {
1028 return false;
1029 }
1030
1031 fp = sysfile_open(resourceFiles[id]);
1032 if (fp == NULL)
1033 {
1034 if (id == Resource_FILELIST)
1035 sys_error("Please install resource files!");
1036 else
1037 sys_error("(resources) unable to open \"%s\"", resourceFiles[id]);
1038 return false;
1039 }
1040
1041 success = readHeader(fp, id);
1042
1043 if (success)
1044 {
1045 switch (id)
1046 {
1047 case Resource_FILELIST: success = loadResourceFilelist(fp); break;
1048 case Resource_PALETTE:
1049 {
1050 vp = game_colors;
1051 success = loadRawData(fp, &vp, sizeof(*game_colors), &game_color_count);
1052 game_colors = vp;
1053 break;
1054 }
1055 case Resource_ENTDATA: success = loadResourceEntdata(fp); break;
1056 case Resource_SPRSEQ:
1057 {
1058 vp = ent_sprseq;
1059 success = loadRawData(fp, &vp, sizeof(*ent_sprseq), &ent_nbr_sprseq);
1060 ent_sprseq = vp;
1061 break;
1062 }
1063 case Resource_MVSTEP:
1064 {
1065 vp = ent_mvstep;
1066 success = loadRawData(fp, &vp, sizeof(*ent_mvstep), &ent_nbr_mvstep);
1067 ent_mvstep = vp;
1068 break;
1069 }
1070 case Resource_MAPS: success = loadResourceMaps(fp); break;
1071 case Resource_SUBMAPS: success = loadResourceSubmaps(fp); break;
1072 case Resource_CONNECT:
1073 {
1074 vp = map_connect;
1075 success = loadRawData(fp, &vp, sizeof(*map_connect), &map_nbr_connect);
1076 map_connect = vp;
1077 break;
1078 }
1079 case Resource_BNUMS:
1080 {
1081 vp = map_bnums;
1082 success = loadRawData(fp, &vp, sizeof(*map_bnums), &map_nbr_bnums);
1083 map_bnums = vp;
1084 break;
1085 }
1086 case Resource_BLOCKS:
1087 {
1088 vp = map_blocks;
1089 success = loadRawData(fp, &vp, sizeof(*map_blocks), &map_nbr_blocks);
1090 map_blocks = vp;
1091 break;
1092 }
1093 case Resource_MARKS:
1094 {
1095 vp = map_marks;
1096 success = loadRawData(fp, &vp, sizeof(*map_marks), &map_nbr_marks);
1097 map_marks = vp;
1098 break;
1099 }
1100 case Resource_EFLGC:
1101 {
1102 vp = map_eflg_c;
1103 success = loadRawData(fp, &vp, sizeof(*map_eflg_c), &map_nbr_eflgc);
1104 map_eflg_c = vp;
1105 break;
1106 }
1107 case Resource_IMAPSL:
1108 {
1109 vp = screen_imapsl;
1110 success = loadRawData(fp, &vp, sizeof(*screen_imapsl), &screen_nbr_imapsl);
1111 screen_imapsl = vp;
1112 break;
1113 }
1114 case Resource_IMAPSTEPS: success = loadResourceImapsteps(fp); break;
1115 case Resource_IMAPSOFS:
1116 {
1117 vp = screen_imapsofs;
1118 success = loadRawData(fp, &vp, sizeof(*screen_imapsofs), &screen_nbr_imapsofs);
1119 screen_imapsofs = vp;
1120 break;
1121 }
1122 case Resource_IMAPTEXT: success = loadResourceImaptext(fp); break;
1123 case Resource_GAMEOVERTXT: success = loadString(fp, (char **)(&screen_gameovertxt), 0xFE); break;
1124 case Resource_PAUSEDTXT: success = loadString(fp, (char **)(&screen_pausedtxt), 0xFE); break;
1125 case Resource_SPRITESDATA: success = loadResourceSpritesData(fp); break;
1126 case Resource_TILESDATA: success = loadResourceTilesData(fp); break;
1127 case Resource_HIGHSCORES: success = loadResourceHighScores(fp); break;
1128 case Resource_IMGSPLASH: success = loadImage(fp, &img_splash); break;
1129#ifdef GFXST
1130 case Resource_PICHAF: success = loadPicture(fp, &pic_haf); break;
1131 case Resource_PICCONGRATS: success = loadPicture(fp, &pic_congrats); break;
1132 case Resource_PICSPLASH: success = loadPicture(fp, &pic_splash); break;
1133#endif /* GFXST */
1134#ifdef GFXPC
1135 case Resource_IMAINHOFT: success = loadString(fp, (char **)(&screen_imainhoft), 0xFE); break;
1136 case Resource_IMAINRDT: success = loadString(fp, (char **)(&screen_imainrdt), 0xFE); break;
1137 case Resource_IMAINCDC: success = loadString(fp, (char **)(&screen_imaincdc), 0xFE); break;
1138 case Resource_SCREENCONGRATS: success = loadString(fp, (char **)(&screen_congrats), 0xFE); break;
1139#endif /* GFXPC */
1140 default: success = false; break;
1141 }
1142 }
1143
1144 if (!success)
1145 {
1146 sys_error("(resources) error when parsing \"%s\"", resourceFiles[id]);
1147 }
1148
1149 sysfile_close(fp);
1150 return success;
1151}
1152
1153/*
1154 *
1155 */
1156bool resources_load()
1157{
1158 bool success;
1159 unsigned id;
1160
1161 /* note: loading order is important: file list first, then sounds, then the rest */
1162
1163 success = readFile(Resource_FILELIST);
1164
1165#ifdef ENABLE_SOUND
1166 for (id = Resource_SOUNDBOMBSHHT; (id <= Resource_SOUNDWALK) && success; ++id)
1167 {
1168 success = loadSound(id);
1169 }
1170#endif /* ENABLE_SOUND */
1171
1172 for (id = Resource_PALETTE; (id <= Resource_SCREENCONGRATS) && success; ++id)
1173 {
1174 success = readFile(id);
1175 }
1176 return success;
1177}
1178
1179/*
1180 *
1181 */
1182void resources_unload()
1183{
1184 int id;
1185 void * vp;
1186
1187 for (id = Resource_SCREENCONGRATS; id >= Resource_PALETTE; --id)
1188 {
1189 switch (id)
1190 {
1191 case Resource_PALETTE:
1192 {
1193 vp = game_colors;
1194 unloadRawData(&vp, &game_color_count);
1195 game_colors = vp;
1196 break;
1197 }
1198 case Resource_ENTDATA: unloadResourceEntdata(); break;
1199 case Resource_SPRSEQ:
1200 {
1201 vp = ent_sprseq;
1202 unloadRawData(&vp, &ent_nbr_sprseq);
1203 ent_sprseq = vp;
1204 break;
1205 }
1206 case Resource_MVSTEP:
1207 {
1208 vp = ent_mvstep;
1209 unloadRawData(&vp, &ent_nbr_mvstep);
1210 ent_mvstep = vp;
1211 break;
1212 }
1213 case Resource_MAPS: unloadResourceMaps(); break;
1214 case Resource_SUBMAPS: unloadResourceSubmaps(); break;
1215 case Resource_CONNECT:
1216 {
1217 vp = map_connect;
1218 unloadRawData(&vp, &map_nbr_connect);
1219 map_connect = vp;
1220 break;
1221 }
1222 case Resource_BNUMS:
1223 {
1224 vp = map_bnums;
1225 unloadRawData(&vp, &map_nbr_bnums);
1226 map_bnums = vp;
1227 break;
1228 }
1229 case Resource_BLOCKS:
1230 {
1231 vp = map_blocks;
1232 unloadRawData(&vp, &map_nbr_blocks);
1233 map_blocks = vp;
1234 break;
1235 }
1236 case Resource_MARKS:
1237 {
1238 vp = map_marks;
1239 unloadRawData(&vp, &map_nbr_marks);
1240 map_marks = vp;
1241 break;
1242 }
1243 case Resource_EFLGC:
1244 {
1245 vp = map_eflg_c;
1246 unloadRawData(&vp, &map_nbr_eflgc);
1247 map_eflg_c = vp;
1248 break;
1249 }
1250 case Resource_IMAPSL:
1251 {
1252 vp = screen_imapsl;
1253 unloadRawData(&vp, &screen_nbr_imapsl);
1254 screen_imapsl = vp;
1255 break;
1256 }
1257 case Resource_IMAPSTEPS: unloadResourceImapsteps(); break;
1258 case Resource_IMAPSOFS:
1259 {
1260 vp = screen_imapsofs;
1261 unloadRawData(&vp, &screen_nbr_imapsofs);
1262 screen_imapsofs = vp;
1263 break;
1264 }
1265 case Resource_IMAPTEXT: unloadResourceImaptext(); break;
1266 case Resource_GAMEOVERTXT: unloadString((char **)(&screen_gameovertxt)); break;
1267 case Resource_PAUSEDTXT: unloadString((char **)(&screen_pausedtxt)); break;
1268 case Resource_SPRITESDATA: unloadResourceSpritesData(); break;
1269 case Resource_TILESDATA: unloadResourceTilesData(); break;
1270 case Resource_HIGHSCORES: unloadResourceHighScores(); break;
1271 case Resource_IMGSPLASH: unloadImage(&img_splash); break;
1272#ifdef GFXST
1273 case Resource_PICHAF: unloadPicture(&pic_haf); break;
1274 case Resource_PICCONGRATS: unloadPicture(&pic_congrats); break;
1275 case Resource_PICSPLASH: unloadPicture(&pic_splash); break;
1276#endif /* GFXST */
1277#ifdef GFXPC
1278 case Resource_IMAINHOFT: unloadString((char **)(&screen_imainhoft)); break;
1279 case Resource_IMAINRDT: unloadString((char **)(&screen_imainrdt)); break;
1280 case Resource_IMAINCDC: unloadString((char **)(&screen_imaincdc)); break;
1281 case Resource_SCREENCONGRATS: unloadString((char **)(&screen_congrats)); break;
1282#endif /* GFXPC */
1283 default: break;
1284 }
1285 }
1286
1287#ifdef ENABLE_SOUND
1288 for (id = Resource_SOUNDWALK; id >= Resource_SOUNDBOMBSHHT; --id)
1289 {
1290 unloadSound(id);
1291 }
1292#endif /* ENABLE_SOUND */
1293
1294 unloadResourceFilelist();
1295}
1296
1297/* eof */
diff --git a/apps/plugins/xrick/resources.h b/apps/plugins/xrick/resources.h
new file mode 100644
index 0000000000..e919ed081a
--- /dev/null
+++ b/apps/plugins/xrick/resources.h
@@ -0,0 +1,165 @@
1/*
2 * xrick/resources.h
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#ifndef _RESOURCES_H
15#define _RESOURCES_H
16
17#include "xrick/config.h"
18#include "xrick/screens.h"
19#include "xrick/system/basic_types.h"
20
21/*
22 * All data is assumed to be Little Endian
23 */
24typedef struct
25{
26 U8 magic[4];
27 U8 version[2];
28 U8 resourceId[2];
29} resource_header_t;
30
31typedef struct
32{
33 U8 w;
34 U8 h;
35 U8 spr[2];
36 U8 sni[2];
37 U8 trig_w;
38 U8 trig_h;
39 U8 snd;
40} resource_entdata_t;
41
42typedef struct
43{
44 U8 x[2];
45 U8 y[2];
46 U8 row[2];
47 U8 submap[2];
48 U8 tuneId[2];
49} resource_map_t;
50
51typedef struct
52{
53 U8 page[2];
54 U8 bnum[2];
55 U8 connect[2];
56 U8 mark[2];
57} resource_submap_t;
58
59typedef struct {
60 U8 count[2];
61 U8 dx[2];
62 U8 dy[2];
63 U8 base[2];
64} resource_imapsteps_t;
65
66typedef struct {
67 U8 width[2];
68 U8 height[2];
69 U8 xPos[2];
70 U8 yPos[2];
71} resource_pic_t;
72
73typedef struct {
74 U8 score[4];
75 U8 name[HISCORE_NAME_SIZE];
76} resource_hiscore_t;
77
78#ifdef GFXPC
79typedef struct {
80 U8 mask[2];
81 U8 pict[2];
82} resource_spriteX_t;
83#endif /* GFXPC */
84
85extern const U8 resource_magic[4];
86
87enum
88{
89 DATA_VERSION = 3,
90
91 /* "bootstrap" file */
92 Resource_FILELIST = 0,
93
94 /* graphics, misc, texts */
95 Resource_PALETTE,
96 Resource_ENTDATA,
97 Resource_SPRSEQ,
98 Resource_MVSTEP,
99 Resource_MAPS,
100 Resource_SUBMAPS,
101 Resource_CONNECT,
102 Resource_BNUMS,
103 Resource_BLOCKS,
104 Resource_MARKS,
105 Resource_EFLGC,
106 Resource_IMAPSL,
107 Resource_IMAPSTEPS,
108 Resource_IMAPSOFS,
109 Resource_IMAPTEXT,
110 Resource_GAMEOVERTXT,
111 Resource_PAUSEDTXT,
112 Resource_SPRITESDATA,
113 Resource_TILESDATA,
114 Resource_HIGHSCORES,
115 Resource_IMGSPLASH,
116 Resource_PICHAF, /* ST version only */
117 Resource_PICCONGRATS, /* ST version only */
118 Resource_PICSPLASH, /* ST version only */
119 Resource_IMAINHOFT, /* PC version only */
120 Resource_IMAINRDT, /* PC version only */
121 Resource_IMAINCDC, /* PC version only */
122 Resource_SCREENCONGRATS, /* PC version only */
123
124 /* sounds */
125 Resource_SOUNDBOMBSHHT,
126 Resource_SOUNDBONUS,
127 Resource_SOUNDBOX,
128 Resource_SOUNDBULLET,
129 Resource_SOUNDCRAWL,
130 Resource_SOUNDDIE,
131 Resource_SOUNDENTITY0,
132 Resource_SOUNDENTITY1,
133 Resource_SOUNDENTITY2,
134 Resource_SOUNDENTITY3,
135 Resource_SOUNDENTITY4,
136 Resource_SOUNDENTITY5,
137 Resource_SOUNDENTITY6,
138 Resource_SOUNDENTITY7,
139 Resource_SOUNDENTITY8,
140 Resource_SOUNDEXPLODE,
141 Resource_SOUNDGAMEOVER,
142 Resource_SOUNDJUMP,
143 Resource_SOUNDPAD,
144 Resource_SOUNDSBONUS1,
145 Resource_SOUNDSBONUS2,
146 Resource_SOUNDSTICK,
147 Resource_SOUNDTUNE0,
148 Resource_SOUNDTUNE1,
149 Resource_SOUNDTUNE2,
150 Resource_SOUNDTUNE3,
151 Resource_SOUNDTUNE4,
152 Resource_SOUNDTUNE5,
153 Resource_SOUNDWALK,
154
155 Resource_MAX_COUNT,
156};
157
158#define BOOTSTRAP_RESOURCE_NAME "filelist.dat"
159
160bool resources_load(void);
161void resources_unload(void);
162
163#endif /* ndef _RESOURCES_H */
164
165/* eof */
diff --git a/apps/plugins/xrick/scr_gameover.c b/apps/plugins/xrick/scr_gameover.c
new file mode 100644
index 0000000000..7467ce3cbe
--- /dev/null
+++ b/apps/plugins/xrick/scr_gameover.c
@@ -0,0 +1,92 @@
1/*
2 * xrick/scr_gameover.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/draw.h"
20#include "xrick/control.h"
21#include "xrick/system/system.h"
22
23/*
24 * Display the game over screen
25 *
26 * return: SCREEN_RUNNING, SCREEN_DONE, SCREEN_EXIT
27 */
28U8
29screen_gameover(void)
30{
31 static U8 seq = 0;
32 static U8 period = 0;
33#ifdef GFXST
34 static U32 tm = 0;
35#endif
36 if (seq == 0) {
37 draw_tilesBank = 0;
38 seq = 1;
39 period = game_period; /* save period, */
40 game_period = 50; /* and use our own */
41#ifdef ENABLE_SOUND
42 game_setmusic(soundGameover, 1);
43#endif
44 }
45
46 switch (seq) {
47 case 1: /* display banner */
48#ifdef GFXST
49 sysvid_clear();
50 tm = sys_gettime();
51#endif
52 draw_tllst = screen_gameovertxt;
53 draw_setfb(120, 80);
54#ifdef GFXPC
55 draw_filter = 0xAAAA;
56#endif
57 draw_tilesList();
58 draw_drawStatus();
59
60 game_rects = &draw_SCREENRECT;
61 seq = 2;
62 break;
63
64 case 2: /* wait for key pressed */
65 if (control_test(Control_FIRE))
66 seq = 3;
67#ifdef GFXST
68 else if (sys_gettime() - tm > SCREEN_TIMEOUT)
69 seq = 4;
70#endif
71 break;
72
73 case 3: /* wait for key released */
74 if (!(control_test(Control_FIRE)))
75 seq = 4;
76 break;
77 }
78
79 if (control_test(Control_EXIT)) /* check for exit request */
80 return SCREEN_EXIT;
81
82 if (seq == 4) { /* we're done */
83 sysvid_clear();
84 seq = 0;
85 game_period = period;
86 return SCREEN_DONE;
87 }
88
89 return SCREEN_RUNNING;
90}
91
92/* eof */
diff --git a/apps/plugins/xrick/scr_getname.c b/apps/plugins/xrick/scr_getname.c
new file mode 100644
index 0000000000..eb1afffde9
--- /dev/null
+++ b/apps/plugins/xrick/scr_getname.c
@@ -0,0 +1,290 @@
1/*
2 * xrick/scr_getname.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/draw.h"
20#include "xrick/control.h"
21#include "xrick/data/pics.h"
22#include "xrick/system/system.h"
23
24/*
25 * local vars
26 */
27static U8 seq = 0;
28static U8 x, y, p;
29static U8 player_name[HISCORE_NAME_SIZE];
30
31#define TILE_POINTER '\072'
32#define TILE_CURSOR '\073'
33#define TOPLEFT_X 116
34#define TOPLEFT_Y 64
35#define NAMEPOS_X 120
36#define NAMEPOS_Y 160
37#define AUTOREPEAT_TMOUT 100
38
39
40/*
41 * prototypes
42 */
43static void pointer_show(bool);
44static void name_update(void);
45static void name_draw(void);
46
47
48/*
49 * Get name
50 *
51 * return: 0 while running, 1 when finished.
52 */
53U8
54screen_getname(void)
55{
56 static U32 tm = 0;
57 U8 i, j;
58
59 if (seq == 0)
60 {
61 /* figure out if this is a high score */
62 if (game_score < screen_highScores[screen_nbr_hiscores - 1].score)
63 return SCREEN_DONE;
64
65 /* prepare */
66 draw_tilesBank = 0;
67#ifdef GFXPC
68 draw_filter = 0xffff;
69#endif
70 for (i = 0; i < HISCORE_NAME_SIZE; i++)
71 {
72 player_name[i] = '@';
73 }
74 x = 5, y = 4, p = 0;
75 game_rects = &draw_SCREENRECT;
76 seq = 1;
77 }
78
79 switch (seq)
80 {
81 case 1: /* prepare screen */
82 {
83 sysvid_clear();
84#ifdef GFXPC
85 draw_setfb(32, 8);
86 draw_filter = 0xaaaa; /* red */
87 draw_tilesListImm(screen_congrats);
88#endif
89#ifdef GFXST
90 draw_pic(pic_congrats);
91#endif
92 draw_setfb(72, 40);
93#ifdef GFXPC
94 draw_filter = 0xffff; /* yellow */
95#endif
96 draw_tilesListImm((U8 *)"PLEASE@ENTER@YOUR@NAME\376");
97#ifdef GFXPC
98 draw_filter = 0x5555; /* green */
99#endif
100 for (i = 0; i < 6; i++)
101 {
102 for (j = 0; j < 4; j++)
103 {
104 draw_setfb(TOPLEFT_X + i * 8 * 2, TOPLEFT_Y + j * 8 * 2);
105 draw_tile('A' + i + j * 6);
106 }
107 }
108 draw_setfb(TOPLEFT_X, TOPLEFT_Y + 64);
109#ifdef GFXST
110 draw_tilesListImm((U8 *)"Y@Z@.@@@\074\373\374\375\376");
111#endif
112#ifdef GFXPC
113 draw_tilesListImm((U8 *)"Y@Z@.@@@\074@\075@\376");
114#endif
115 name_draw();
116 pointer_show(true);
117 seq = 2;
118 break;
119 }
120 case 2: /* wait for key pressed */
121 {
122 if (control_test(Control_FIRE))
123 seq = 3;
124 if (control_test(Control_UP)) {
125 if (y > 0) {
126 pointer_show(false);
127 y--;
128 pointer_show(true);
129 tm = sys_gettime();
130 }
131 seq = 4;
132 }
133 if (control_test(Control_DOWN)) {
134 if (y < 4) {
135 pointer_show(false);
136 y++;
137 pointer_show(true);
138 tm = sys_gettime();
139 }
140 seq = 5;
141 }
142 if (control_test(Control_LEFT)) {
143 if (x > 0) {
144 pointer_show(false);
145 x--;
146 pointer_show(true);
147 tm = sys_gettime();
148 }
149 seq = 6;
150 }
151 if (control_test(Control_RIGHT)) {
152 if (x < 5) {
153 pointer_show(false);
154 x++;
155 pointer_show(true);
156 tm = sys_gettime();
157 }
158 seq = 7;
159 }
160 break;
161 }
162 case 3: /* wait for FIRE released */
163 {
164 if (!(control_test(Control_FIRE)))
165 {
166 if (x == 5 && y == 4)
167 { /* end */
168 i = 0;
169 while (game_score < screen_highScores[i].score) i++;
170 j = 7;
171 while (j > i)
172 {
173 screen_highScores[j].score = screen_highScores[j - 1].score;
174 for (x = 0; x < HISCORE_NAME_SIZE; x++)
175 {
176 screen_highScores[j].name[x] = screen_highScores[j - 1].name[x];
177 }
178 j--;
179 }
180 screen_highScores[i].score = game_score;
181 for (x = 0; x < HISCORE_NAME_SIZE; x++)
182 {
183 screen_highScores[i].name[x] = player_name[x];
184 }
185 seq = 99;
186 }
187 else
188 {
189 name_update();
190 name_draw();
191 seq = 2;
192 }
193 }
194 break;
195 }
196 case 4: /* wait for UP released */
197 {
198 if (!(control_test(Control_UP)) ||
199 sys_gettime() - tm > AUTOREPEAT_TMOUT)
200 seq = 2;
201 break;
202 }
203 case 5: /* wait for DOWN released */
204 {
205 if (!(control_test(Control_DOWN)) ||
206 sys_gettime() - tm > AUTOREPEAT_TMOUT)
207 seq = 2;
208 break;
209 }
210 case 6: /* wait for LEFT released */
211 {
212 if (!(control_test(Control_LEFT)) ||
213 sys_gettime() - tm > AUTOREPEAT_TMOUT)
214 seq = 2;
215 break;
216 }
217 case 7: /* wait for RIGHT released */
218 {
219 if (!(control_test(Control_RIGHT)) ||
220 sys_gettime() - tm > AUTOREPEAT_TMOUT)
221 seq = 2;
222 break;
223 }
224 }
225
226 if (control_test(Control_EXIT)) /* check for exit request */
227 return SCREEN_EXIT;
228
229 if (seq == 99) { /* seq 99, we're done */
230 sysvid_clear();
231 seq = 0;
232 return SCREEN_DONE;
233 }
234 else
235 return SCREEN_RUNNING;
236}
237
238
239static void
240pointer_show(bool show)
241{
242 draw_setfb(TOPLEFT_X + x * 8 * 2, TOPLEFT_Y + y * 8 * 2 + 8);
243#ifdef GFXPC
244 draw_filter = 0xaaaa; /* red */
245#endif
246 draw_tile(show? TILE_POINTER:'@');
247}
248
249static void
250name_update(void)
251{
252 U8 i;
253
254 i = x + y * 6;
255 if (i < 26 && p < 10)
256 player_name[p++] = 'A' + i;
257 if (i == 26 && p < 10)
258 player_name[p++] = '.';
259 if (i == 27 && p < 10)
260 player_name[p++] = '@';
261 if (i == 28 && p > 0) {
262 p--;
263 }
264}
265
266static void
267name_draw(void)
268{
269 U8 i;
270
271 draw_setfb(NAMEPOS_X, NAMEPOS_Y);
272#ifdef GFXPC
273 draw_filter = 0xaaaa; /* red */
274#endif
275 for (i = 0; i < p; i++)
276 draw_tile(player_name[i]);
277 for (i = p; i < 10; i++)
278 draw_tile(TILE_CURSOR);
279
280#ifdef GFXST
281 draw_setfb(NAMEPOS_X, NAMEPOS_Y + 8);
282 for (i = 0; i < 10; i++)
283 draw_tile('@');
284 draw_setfb(NAMEPOS_X + 8 * (p < 9 ? p : 9), NAMEPOS_Y + 8);
285 draw_tile(TILE_POINTER);
286#endif
287}
288
289
290/* eof */
diff --git a/apps/plugins/xrick/scr_imain.c b/apps/plugins/xrick/scr_imain.c
new file mode 100644
index 0000000000..6851cd0cca
--- /dev/null
+++ b/apps/plugins/xrick/scr_imain.c
@@ -0,0 +1,170 @@
1/*
2 * xrick/scr_imain.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/draw.h"
20#include "xrick/control.h"
21#ifdef GFXST
22#include "xrick/data/pics.h"
23#endif
24#include "xrick/system/system.h"
25
26/*
27 * Main introduction
28 *
29 * return: SCREEN_RUNNING, SCREEN_DONE, SCREEN_EXIT
30 */
31U8
32screen_introMain(void)
33{
34 static U8 seq = 0;
35 static U8 seen = 0;
36 static bool first = true;
37 static U8 period = 0;
38 static U32 tm = 0;
39
40 if (seq == 0) {
41 draw_tilesBank = 0;
42 if (first)
43 seq = 1;
44 else
45 seq = 4;
46 period = game_period;
47 game_period = 50;
48 game_rects = &draw_SCREENRECT;
49#ifdef ENABLE_SOUND
50 game_setmusic(soundTune5, -1);
51#endif
52 }
53
54 switch (seq)
55 {
56 case 1: /* display Rick Dangerous title and Core Design copyright */
57 {
58 sysvid_clear();
59 tm = sys_gettime();
60#ifdef GFXPC
61 /* Rick Dangerous title */
62 draw_tllst = (U8 *)screen_imainrdt;
63 draw_setfb(32, 16);
64 draw_filter = 0xaaaa;
65 draw_tilesList();
66
67 /* Core Design copyright + press space to start */
68 draw_tllst = (U8 *)screen_imaincdc;
69 draw_setfb(64, 80);
70 draw_filter = 0x5555;
71 draw_tilesList();
72#endif
73#ifdef GFXST
74 draw_pic(pic_splash);
75#endif
76 seq = 2;
77 break;
78 }
79 case 2: /* wait for key pressed or timeout */
80 {
81 if (control_test(Control_FIRE))
82 seq = 3;
83 else if (sys_gettime() - tm > SCREEN_TIMEOUT) {
84 seen++;
85 seq = 4;
86 }
87 break;
88 }
89 case 3: /* wait for key released */
90 {
91 if (!(control_test(Control_FIRE))) {
92 if (seen++ == 0)
93 seq = 4;
94 else
95 seq = 7;
96 }
97 break;
98 }
99 case 4: /* dispay hall of fame */
100 {
101 U8 s[32];
102 size_t i;
103
104 sysvid_clear();
105 tm = sys_gettime();
106 /* hall of fame title */
107#ifdef GFXPC
108 draw_tllst = (U8 *)screen_imainhoft;
109 draw_setfb(32, 0);
110 draw_filter = 0xaaaa;
111 draw_tilesList();
112#endif
113#ifdef GFXST
114 draw_pic(pic_haf);
115#endif
116 /* hall of fame content */
117 draw_setfb(56, 48);
118#ifdef GFXPC
119 draw_filter = 0x5555;
120#endif
121 for (i = 0; i < screen_nbr_hiscores; i++) {
122 sys_snprintf((char *)s, sizeof(s), "%06d@@@====@@@%s",
123 screen_highScores[i].score, screen_highScores[i].name);
124 s[26] = (U8)'\377';
125 s[27] = (U8)'\377';
126 s[28] = (U8)'\376';
127 draw_tllst = s;
128 draw_tilesList();
129 }
130 seq = 5;
131 break;
132 }
133 case 5: /* wait for key pressed or timeout */
134 {
135 if (control_test(Control_FIRE))
136 seq = 6;
137 else if (sys_gettime() - tm > SCREEN_TIMEOUT) {
138 seen++;
139 seq = 1;
140 }
141 break;
142 }
143 case 6: /* wait for key released */
144 {
145 if (!(control_test(Control_FIRE))) {
146 if (seen++ == 0)
147 seq = 1;
148 else
149 seq = 7;
150 }
151 break;
152 }
153 }
154
155 if (control_test(Control_EXIT)) /* check for exit request */
156 return SCREEN_EXIT;
157
158 if (seq == 7) { /* we're done */
159 sysvid_clear();
160 seq = 0;
161 seen = 0;
162 first = false;
163 game_period = period;
164 return SCREEN_DONE;
165 }
166 else
167 return SCREEN_RUNNING;
168}
169
170/* eof */
diff --git a/apps/plugins/xrick/scr_imap.c b/apps/plugins/xrick/scr_imap.c
new file mode 100644
index 0000000000..5be80a24e4
--- /dev/null
+++ b/apps/plugins/xrick/scr_imap.c
@@ -0,0 +1,293 @@
1/*
2 * xrick/scr_imap.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/rects.h"
20#include "xrick/draw.h"
21#include "xrick/control.h"
22#include "xrick/maps.h"
23
24/*
25 * local vars
26 */
27static U16 step; /* current step */
28static U16 count; /* number of loops for current step */
29static U16 run; /* 1 = run, 0 = no more step */
30static U8 flipflop; /* flipflop for top, bottom, left, right */
31static U8 spnum; /* sprite number */
32static U16 spx, spdx; /* sprite x position and delta */
33static U16 spy, spdy; /* sprite y position and delta */
34static U16 spbase, spoffs; /* base, offset for sprite numbers table */
35static U8 seq = 0; /* anim sequence */
36
37static rect_t anim_rect = { 128, 16 + 16, 64, 64, NULL }; /* anim rectangle */
38
39/*
40 * prototypes
41 */
42static void drawtb(void);
43static void drawlr(void);
44static void drawsprite(void);
45static void drawcenter(void);
46static void nextstep(void);
47static void anim(void);
48static void init(void);
49
50/*
51 * Map introduction
52 *
53 * ASM: 1948
54 *
55 * return: SCREEN_RUNNING, SCREEN_DONE, SCREEN_EXIT
56 */
57U8
58screen_introMap(void)
59{
60 switch (seq) {
61 case 0:
62 sysvid_clear();
63
64#ifdef GFXPC
65 draw_tilesBank = 1;
66 draw_filter = 0xAAAA;
67#endif
68#ifdef GFXST
69 draw_tilesBank = 0;
70#endif
71 draw_tllst = screen_imaptext[game_map];
72 draw_setfb(40, 16);
73 draw_tilesSubList();
74
75 draw_setfb(40, 104);
76#ifdef GFXPC
77 draw_filter = 0x5555;
78#endif
79 draw_tilesList();
80
81 game_rects = NULL;
82
83#ifdef GFXPC
84 draw_filter = 0xFFFF;
85#endif
86
87 init();
88 nextstep();
89 drawcenter();
90 drawtb();
91 drawlr();
92 drawsprite();
93 draw_drawStatus();
94
95 game_rects = &draw_SCREENRECT;
96
97#ifdef ENABLE_SOUND
98 game_setmusic(map_maps[game_map].tune, 1);
99#endif
100
101 seq = 1;
102 break;
103 case 1: /* top and bottom borders */
104 drawtb();
105 game_rects = &anim_rect;
106 seq = 2;
107 break;
108 case 2: /* background and sprite */
109 anim();
110 drawcenter();
111 drawsprite();
112 game_rects = &anim_rect;
113 seq = 3;
114 break;
115 case 3: /* all borders */
116 drawtb();
117 drawlr();
118 game_rects = &anim_rect;
119 seq = 1;
120 break;
121 case 4: /* wait for key release */
122 if (!(control_test(Control_FIRE)))
123 seq = 5;
124 break;
125 }
126
127 if (control_test(Control_FIRE)) { /* end as soon as key pressed */
128 seq = 4;
129 }
130
131 if (control_test(Control_EXIT)) /* check for exit request */
132 return SCREEN_EXIT;
133
134 if (seq == 5) { /* end as soon as key pressed */
135 sysvid_clear();
136 seq = 0;
137 return SCREEN_DONE;
138 }
139 else
140 return SCREEN_RUNNING;
141}
142
143
144/*
145 * Display top and bottom borders (0x1B1F)
146 *
147 */
148static void
149drawtb(void)
150{
151 U8 i;
152
153 flipflop++;
154 if (flipflop & 0x01) {
155 draw_setfb(136, 16 + 16);
156 for (i = 0; i < 6; i++)
157 draw_tile(0x40);
158 draw_setfb(136, 72 + 16);
159 for (i = 0; i < 6; i++)
160 draw_tile(0x06);
161 }
162 else {
163 draw_setfb(136, 16 + 16);
164 for (i = 0; i < 6; i++)
165 draw_tile(0x05);
166 draw_setfb(136, 72 + 16);
167 for (i = 0; i < 6; i++)
168 draw_tile(0x40);
169 }
170}
171
172
173/*
174 * Display left and right borders (0x1B7C)
175 *
176 */
177static void
178drawlr(void)
179{
180 U8 i;
181
182 if (flipflop & 0x02) {
183 for (i = 0; i < 8; i++) {
184 draw_setfb(128, 16 + i * 8 + 16);
185 draw_tile(0x04);
186 draw_setfb(184, 16 + i * 8 + 16);
187 draw_tile(0x04);
188 }
189 }
190 else {
191 for (i = 0; i < 8; i++) {
192 draw_setfb(128, 16 + i * 8 + 16);
193 draw_tile(0x2B);
194 draw_setfb(184, 16 + i * 8 + 16);
195 draw_tile(0x2B);
196 }
197 }
198}
199
200
201/*
202 * Draw the sprite (0x19C6)
203 *
204 */
205static void
206drawsprite(void)
207{
208 draw_sprite(spnum, 136 + ((spx << 1) & 0x1C), 24 + (spy << 1) + 16);
209}
210
211
212/*
213 * Draw the background (0x1AF1)
214 *
215 */
216static void
217drawcenter(void)
218{
219 static U8 tn0[] = { 0x07, 0x5B, 0x7F, 0xA3, 0xC7 };
220 U8 i, j, tn;
221
222 tn = tn0[game_map];
223 for (i = 0; i < 6; i++) {
224 draw_setfb(136, (24 + 8 * i) + 16);
225 for (j = 0; j < 6; j++)
226 draw_tile(tn++);
227 }
228}
229
230
231/*
232 * Next Step (0x1A74)
233 *
234 */
235static void
236nextstep(void)
237{
238 if (screen_imapsteps[step].count) {
239 count = screen_imapsteps[step].count;
240 spdx = screen_imapsteps[step].dx;
241 spdy = screen_imapsteps[step].dy;
242 spbase = screen_imapsteps[step].base;
243 spoffs = 0;
244 step++;
245 }
246 else {
247 run = 0;
248 }
249}
250
251
252/*
253 * Anim (0x1AA8)
254 *
255 */
256static void
257anim(void)
258{
259 U8 i;
260
261 if (run) {
262 i = screen_imapsl[spbase + spoffs];
263 if (i == 0) {
264 spoffs = 0;
265 i = screen_imapsl[spbase];
266 }
267 spnum = i;
268 spoffs++;
269 spx += spdx;
270 spy += spdy;
271 count--;
272 if (count == 0)
273 nextstep();
274 }
275}
276
277
278/*
279 * Initialize (0x1A43)
280 *
281 */
282static void
283init(void)
284{
285 run = 0; run--;
286 step = screen_imapsofs[game_map];
287 spx = screen_imapsteps[step].dx;
288 spy = screen_imapsteps[step].dy;
289 step++;
290 spnum = 0; /* NOTE spnum in [8728] is never initialized ? */
291}
292
293/* eof */
diff --git a/apps/plugins/xrick/scr_pause.c b/apps/plugins/xrick/scr_pause.c
new file mode 100644
index 0000000000..04c3368d21
--- /dev/null
+++ b/apps/plugins/xrick/scr_pause.c
@@ -0,0 +1,50 @@
1/*
2 * xrick/scr_pause.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/draw.h"
20#include "xrick/control.h"
21#include "xrick/ents.h"
22
23/*
24 * Display the pause indicator
25 */
26void
27screen_pause(bool pause)
28{
29 if (pause) {
30 draw_tilesBank = 0;
31 draw_tllst = screen_pausedtxt;
32 draw_setfb(120, 80);
33#ifdef GFXPC
34 draw_filter = 0xAAAA;
35#endif
36 draw_tilesList();
37 }
38 else {
39#ifdef GFXPC
40 draw_filter = 0xFFFF;
41#endif
42 draw_map();
43 ent_draw();
44 draw_drawStatus();
45 }
46 game_rects = &draw_SCREENRECT;
47}
48
49
50/* eof */
diff --git a/apps/plugins/xrick/scr_xrick.c b/apps/plugins/xrick/scr_xrick.c
new file mode 100644
index 0000000000..00798ec123
--- /dev/null
+++ b/apps/plugins/xrick/scr_xrick.c
@@ -0,0 +1,101 @@
1/*
2 * xrick/scr_xrick.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/screens.h"
17
18#include "xrick/game.h"
19#include "xrick/draw.h"
20#include "xrick/control.h"
21#include "xrick/data/img.h"
22#include "xrick/system/system.h"
23
24/*
25 * global vars
26 */
27size_t screen_nbr_imapsl = 0;
28U8 *screen_imapsl = NULL;
29
30size_t screen_nbr_imapstesps = 0;
31screen_imapsteps_t *screen_imapsteps = NULL;
32
33size_t screen_nbr_imapsofs = 0;
34U8 *screen_imapsofs = NULL;
35
36size_t screen_nbr_imaptext = 0;
37U8 **screen_imaptext = NULL;
38
39size_t screen_nbr_hiscores = 0;
40hiscore_t *screen_highScores = NULL;
41
42#ifdef GFXPC
43U8 *screen_imainhoft = NULL;
44U8 *screen_imainrdt = NULL;
45U8 *screen_imaincdc = NULL;
46U8 *screen_congrats = NULL;
47#endif
48U8 *screen_gameovertxt = NULL;
49U8 *screen_pausedtxt = NULL;
50
51
52/*
53 * Display XRICK splash screen
54 *
55 * return: SCREEN_RUNNING, SCREEN_DONE, SCREEN_EXIT
56 */
57U8
58screen_xrick(void)
59{
60 static U8 seq = 0;
61 static U8 wait = 0;
62
63 if (seq == 0) {
64 sysvid_clear();
65 draw_img(img_splash);
66 game_rects = &draw_SCREENRECT;
67 seq = 1;
68 }
69
70 switch (seq) {
71 case 1: /* wait */
72 if (wait++ > 0x2) {
73#ifdef ENABLE_SOUND
74 game_setmusic(soundBullet, 1);
75#endif
76 seq = 2;
77 wait = 0;
78 }
79 break;
80
81 case 2: /* wait */
82 if (wait++ > 0x20) {
83 seq = 99;
84 wait = 0;
85 }
86 }
87
88 if (control_test(Control_EXIT)) /* check for exit request */
89 return SCREEN_EXIT;
90
91 if (seq == 99) { /* we're done */
92 sysvid_clear();
93 sysvid_setGamePalette();
94 seq = 0;
95 return SCREEN_DONE;
96 }
97
98 return SCREEN_RUNNING;
99}
100
101/* eof */
diff --git a/apps/plugins/xrick/screens.h b/apps/plugins/xrick/screens.h
new file mode 100644
index 0000000000..60564a99d2
--- /dev/null
+++ b/apps/plugins/xrick/screens.h
@@ -0,0 +1,74 @@
1/*
2 * xrick/screens.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _SCREENS_H
17#define _SCREENS_H
18
19#include "xrick/system/basic_types.h"
20#include "xrick/config.h"
21
22#include <stddef.h> /* size_t */
23
24#define SCREEN_TIMEOUT 4000
25#define SCREEN_RUNNING 0
26#define SCREEN_DONE 1
27#define SCREEN_EXIT 2
28
29typedef struct {
30 U16 count; /* number of loops */
31 U16 dx, dy; /* sprite x and y deltas */
32 U16 base; /* base for sprite numbers table */
33} screen_imapsteps_t; /* description of one step */
34
35enum { HISCORE_NAME_SIZE = 10 };
36typedef struct {
37 U32 score;
38 U8 name[HISCORE_NAME_SIZE];
39} hiscore_t;
40
41extern size_t screen_nbr_imapsl;
42extern U8 *screen_imapsl; /* sprite lists */
43
44extern size_t screen_nbr_imapstesps;
45extern screen_imapsteps_t *screen_imapsteps; /* map intro steps */
46
47extern size_t screen_nbr_imapsofs;
48extern U8 *screen_imapsofs; /* first step for each map */
49
50extern size_t screen_nbr_imaptext;
51extern U8 **screen_imaptext; /* map intro texts */
52
53extern size_t screen_nbr_hiscores;
54extern hiscore_t *screen_highScores; /* highest scores (hall of fame) */
55
56#ifdef GFXPC
57extern U8 *screen_imainhoft; /* hall of fame title */
58extern U8 *screen_imainrdt; /* rick dangerous title */
59extern U8 *screen_imaincdc; /* core design copyright text */
60extern U8 *screen_congrats; /* congratulations */
61#endif /* GFXPC */
62extern U8 *screen_gameovertxt; /* game over */
63extern U8 *screen_pausedtxt; /* paused */
64
65extern U8 screen_xrick(void); /* splash */
66extern U8 screen_introMain(void); /* main intro */
67extern U8 screen_introMap(void); /* map intro */
68extern U8 screen_gameover(void); /* gameover */
69extern U8 screen_getname(void); /* enter you name */
70extern void screen_pause(bool); /* pause indicator */
71
72#endif /* ndef _SCREENS_H */
73
74/* eof */
diff --git a/apps/plugins/xrick/scroller.c b/apps/plugins/xrick/scroller.c
new file mode 100644
index 0000000000..824fe9a6a9
--- /dev/null
+++ b/apps/plugins/xrick/scroller.c
@@ -0,0 +1,165 @@
1/*
2 * xrick/scroller.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/scroller.h"
17
18#include "xrick/game.h"
19#include "xrick/debug.h"
20#include "xrick/draw.h"
21#include "xrick/maps.h"
22#include "xrick/ents.h"
23
24/*
25 * Local variables
26 */
27static U8 period;
28
29/*
30 * Scroll up
31 *
32 */
33U8
34scroll_up(void)
35{
36 U8 i, j;
37 static U8 n = 0;
38
39 /* last call: restore */
40 if (n == 8) {
41 n = 0;
42 game_period = period;
43 return SCROLL_DONE;
44 }
45
46 /* first call: prepare */
47 if (n == 0) {
48 period = game_period;
49 game_period = SCROLL_PERIOD;
50 }
51
52 /* translate map */
53 for (i = MAP_ROW_SCRTOP; i < MAP_ROW_HBBOT; i++)
54 for (j = 0x00; j < 0x20; j++)
55 map_map[i][j] = map_map[i + 1][j];
56
57 /* translate entities */
58 for (i = 0; ent_ents[i].n != 0xFF; i++) {
59 if (ent_ents[i].n) {
60 ent_ents[i].ysave -= 8;
61 ent_ents[i].trig_y -= 8;
62 ent_ents[i].y -= 8;
63 if (ent_ents[i].y & 0x8000) { /* map coord. from 0x0000 to 0x0140 */
64 IFDEBUG_SCROLLER(
65 sys_printf("xrick/scroller: entity %#04X is gone\n", i);
66 );
67 ent_ents[i].n = 0;
68 }
69 }
70 }
71
72 /* display */
73 draw_map();
74 ent_draw();
75 draw_drawStatus();
76 map_frow++;
77
78 /* loop */
79 if (n++ == 7) {
80 /* activate visible entities */
81 ent_actvis(map_frow + MAP_ROW_HBTOP, map_frow + MAP_ROW_HBBOT);
82
83 /* prepare map */
84 map_expand();
85
86 /* display */
87 draw_map();
88 ent_draw();
89 draw_drawStatus();
90 }
91
92 game_rects = &draw_SCREENRECT;
93
94 return SCROLL_RUNNING;
95}
96
97/*
98 * Scroll down
99 *
100 */
101U8
102scroll_down(void)
103{
104 U8 i, j;
105 static U8 n = 0;
106
107 /* last call: restore */
108 if (n == 8) {
109 n = 0;
110 game_period = period;
111 return SCROLL_DONE;
112 }
113
114 /* first call: prepare */
115 if (n == 0) {
116 period = game_period;
117 game_period = SCROLL_PERIOD;
118 }
119
120 /* translate map */
121 for (i = MAP_ROW_SCRBOT; i > MAP_ROW_HTTOP; i--)
122 for (j = 0x00; j < 0x20; j++)
123 map_map[i][j] = map_map[i - 1][j];
124
125 /* translate entities */
126 for (i = 0; ent_ents[i].n != 0xFF; i++) {
127 if (ent_ents[i].n) {
128 ent_ents[i].ysave += 8;
129 ent_ents[i].trig_y += 8;
130 ent_ents[i].y += 8;
131 if (ent_ents[i].y > 0x0140) { /* map coord. from 0x0000 to 0x0140 */
132 IFDEBUG_SCROLLER(
133 sys_printf("xrick/scroller: entity %#04X is gone\n", i);
134 );
135 ent_ents[i].n = 0;
136 }
137 }
138 }
139
140 /* display */
141 draw_map();
142 ent_draw();
143 draw_drawStatus();
144 map_frow--;
145
146 /* loop */
147 if (n++ == 7) {
148 /* activate visible entities */
149 ent_actvis(map_frow + MAP_ROW_HTTOP, map_frow + MAP_ROW_HTBOT);
150
151 /* prepare map */
152 map_expand();
153
154 /* display */
155 draw_map();
156 ent_draw();
157 draw_drawStatus();
158 }
159
160 game_rects = &draw_SCREENRECT;
161
162 return SCROLL_RUNNING;
163}
164
165/* eof */
diff --git a/apps/plugins/xrick/scroller.h b/apps/plugins/xrick/scroller.h
new file mode 100644
index 0000000000..50c2190547
--- /dev/null
+++ b/apps/plugins/xrick/scroller.h
@@ -0,0 +1,31 @@
1/*
2 * xrick/scroller.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _SCROLLER_H
17#define _SCROLLER_H
18
19#define SCROLL_RUNNING 1
20#define SCROLL_DONE 0
21
22#define SCROLL_PERIOD 24
23
24#include "xrick/system/basic_types.h"
25
26extern U8 scroll_up(void);
27extern U8 scroll_down(void);
28
29#endif /* ndef _SCROLLER_H */
30
31/* eof */
diff --git a/apps/plugins/xrick/system/basic_funcs.c b/apps/plugins/xrick/system/basic_funcs.c
new file mode 100644
index 0000000000..fbc025a6ef
--- /dev/null
+++ b/apps/plugins/xrick/system/basic_funcs.c
@@ -0,0 +1,33 @@
1/*
2 * xrick/system/basic_funcs.c
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#include "xrick/system/basic_funcs.h"
15
16#ifdef USE_DEFAULT_ENDIANNESS_FUNCTIONS
17
18extern inline uint16_t swap16(uint16_t x);
19extern inline uint32_t swap32(uint32_t x);
20
21extern inline uint16_t htobe16(uint16_t host);
22extern inline uint16_t htole16(uint16_t host);
23extern inline uint16_t betoh16(uint16_t big_endian);
24extern inline uint16_t letoh16(uint16_t little_endian);
25
26extern inline uint32_t htobe32(uint32_t host);
27extern inline uint32_t htole32(uint32_t host);
28extern inline uint32_t betoh32(uint32_t big_endian);
29extern inline uint32_t letoh32(uint32_t little_endian);
30
31#endif /* USE_DEFAULT_ENDIANNESS_FUNCTIONS */
32
33/* eof */
diff --git a/apps/plugins/xrick/system/basic_funcs.h b/apps/plugins/xrick/system/basic_funcs.h
new file mode 100644
index 0000000000..1ac5c58d32
--- /dev/null
+++ b/apps/plugins/xrick/system/basic_funcs.h
@@ -0,0 +1,141 @@
1/*
2 * xrick/system/basic_funcs.h
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#ifndef _BASIC_FUNCS_H
15#define _BASIC_FUNCS_H
16
17#include "xrick/system/basic_types.h"
18#include "xrick/system/system.h"
19
20#ifdef __WIN32__
21/* Windows is little endian only */
22# define __ORDER_LITTLE_ENDIAN__ 1234
23# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
24# define USE_DEFAULT_ENDIANNESS_FUNCTIONS
25# include <stdlib.h> /* _byteswap_XXX */
26
27#elif defined(ROCKBOX)
28/* Rockbox*/
29# include "plugin.h"
30# define __ORDER_LITTLE_ENDIAN__ 1234
31# define __ORDER_BIG_ENDIAN__ 4321
32# ifdef ROCKBOX_BIG_ENDIAN
33# define __BYTE_ORDER__ __ORDER_BIG_ENDIAN__
34# else
35# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
36# endif
37
38#elif (defined(__FreeBSD__) && __FreeBSD_version >= 470000) || defined(__OpenBSD__) || defined(__NetBSD__)
39/* *BSD */
40# include <sys/endian.h>
41# define __ORDER_BIG_ENDIAN__ BIG_ENDIAN
42# define __ORDER_LITTLE_ENDIAN__ LITTLE_ENDIAN
43# define __BYTE_ORDER__ BYTE_ORDER
44
45#elif (defined(BSD) && (BSD >= 199103)) || defined(__MacOSX__)
46/* more BSD */
47# include <machine/endian.h>
48# define __ORDER_BIG_ENDIAN__ BIG_ENDIAN
49# define __ORDER_LITTLE_ENDIAN__ LITTLE_ENDIAN
50# define __BYTE_ORDER__ BYTE_ORDER
51
52#elif defined(__linux__) /*|| defined (__BEOS__)*/
53/* Linux, BeOS */
54# include <endian.h>
55# define betoh16(x) be16toh(x)
56# define letoh16(x) le16toh(x)
57# define betoh32(x) be32toh(x)
58# define letoh32(x) le32toh(x)
59
60#else
61/* shall we just '#include <endian.h>'? */
62# define USE_DEFAULT_ENDIANNESS_FUNCTIONS
63
64#endif /* __WIN32__ */
65
66/* define default endianness */
67#ifndef __ORDER_LITTLE_ENDIAN__
68# define __ORDER_LITTLE_ENDIAN__ 1234
69#endif
70
71#ifndef __ORDER_BIG_ENDIAN__
72# define __ORDER_BIG_ENDIAN__ 4321
73#endif
74
75#ifndef __BYTE_ORDER__
76# warning "Byte order not defined on your system, assuming little endian!"
77# define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__
78#endif
79
80/* provide default endianness functions */
81#ifdef USE_DEFAULT_ENDIANNESS_FUNCTIONS
82
83# define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
84
85inline uint32_t swap32(uint32_t x)
86{
87# ifdef _MSC_VER
88 return _byteswap_ulong(x);
89# elif (GCC_VERSION > 40300) || defined(__clang__)
90 return __builtin_bswap32(x);
91# else
92 return (x >> 24) |
93 ((x >> 8) & 0x0000FF00) |
94 ((x << 8) & 0x00FF0000) |
95 (x << 24);
96# endif /* _MSC_VER */
97}
98
99inline uint16_t swap16(uint16_t x)
100{
101# ifdef _MSC_VER
102 return _byteswap_ushort(x);
103# elif (GCC_VERSION > 40800) || defined(__clang__)
104 return __builtin_bswap16(x);
105# else
106 return (x << 8)|(x >> 8);
107# endif /* _MSC_VER */
108}
109
110# if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__)
111inline uint16_t htobe16(uint16_t host) { return swap16(host); }
112inline uint16_t htole16(uint16_t host) { return host; }
113inline uint16_t betoh16(uint16_t big_endian) { return swap16(big_endian); }
114inline uint16_t letoh16(uint16_t little_endian) { return little_endian; }
115
116inline uint32_t htobe32(uint32_t host) { return swap32(host); }
117inline uint32_t htole32(uint32_t host) { return host; }
118inline uint32_t betoh32(uint32_t big_endian) { return swap32(big_endian); }
119inline uint32_t letoh32(uint32_t little_endian) { return little_endian; }
120
121# elif (__BYTE_ORDER__==__ORDER_BIG_ENDIAN__)
122inline uint16_t htobe16(uint16_t host) { return host; }
123inline uint16_t htole16(uint16_t host) { return swap16(host); }
124inline uint16_t betoh16(uint16_t big_endian) { return big_endian; }
125inline uint16_t letoh16(uint16_t little_endian) { return swap16(little_endian); }
126
127inline uint32_t htobe32(uint32_t host) { return host; }
128inline uint32_t htole32(uint32_t host) { return swap32(host); }
129inline uint32_t betoh32(uint32_t big_endian) { return big_endian; }
130inline uint32_t letoh32(uint32_t little_endian) { return swap32(little_endian); }
131
132# else
133# error "Unknown/unsupported byte order!"
134
135# endif
136
137#endif /* USE_DEFAULT_ENDIANNESS_FUNCTIONS */
138
139#endif /* ndef _BASIC_FUNCS_H */
140
141/* eof */
diff --git a/apps/plugins/xrick/system/basic_types.h b/apps/plugins/xrick/system/basic_types.h
new file mode 100644
index 0000000000..e05fd477f3
--- /dev/null
+++ b/apps/plugins/xrick/system/basic_types.h
@@ -0,0 +1,48 @@
1/*
2 * xrick/system/basic_types.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _BASIC_TYPES_H
17#define _BASIC_TYPES_H
18
19#ifdef _MSC_VER
20
21typedef enum { false, true } bool;
22
23#define inline __inline
24
25typedef unsigned __int8 uint8_t;
26typedef unsigned __int16 uint16_t;
27typedef unsigned __int32 uint32_t;
28typedef __int8 int8_t;
29typedef __int16 int16_t;
30typedef __int32 int32_t;
31
32#else /* ndef _MSC_VER */
33
34#include <stdbool.h>
35#include <stdint.h>
36
37#endif /* _MSC_VER */
38
39typedef uint8_t U8; /* 8 bits unsigned */
40typedef uint16_t U16; /* 16 bits unsigned */
41typedef uint32_t U32; /* 32 bits unsigned */
42typedef int8_t S8; /* 8 bits signed */
43typedef int16_t S16; /* 16 bits signed */
44typedef int32_t S32; /* 32 bits signed */
45
46#endif /* ndef _BASIC_TYPES_H */
47
48/* eof */
diff --git a/apps/plugins/xrick/system/main_rockbox.c b/apps/plugins/xrick/system/main_rockbox.c
new file mode 100644
index 0000000000..e273e1dc8d
--- /dev/null
+++ b/apps/plugins/xrick/system/main_rockbox.c
@@ -0,0 +1,43 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26#include "xrick/game.h"
27
28#include "plugin.h"
29
30/* Plug-in entry point */
31enum plugin_status plugin_start(const void* parameter)
32{
33 char *filename = (char*)parameter;
34 bool success = sys_init(1, &filename);
35 if (success)
36 {
37 game_run();
38 }
39 sys_shutdown();
40 return (success? PLUGIN_OK : PLUGIN_ERROR);
41}
42
43/* eof */
diff --git a/apps/plugins/xrick/system/miniz_config.h b/apps/plugins/xrick/system/miniz_config.h
new file mode 100644
index 0000000000..65899b0c23
--- /dev/null
+++ b/apps/plugins/xrick/system/miniz_config.h
@@ -0,0 +1,38 @@
1/*
2 * xrick/system/miniz_config.h
3 *
4 * Copyright (C) 2008-2014 Pierluigi Vicinanza. All rights reserved.
5 *
6 * The use and distribution terms for this software are contained in the file
7 * named README, which can be found in the root of this distribution. By
8 * using this software in any fashion, you are agreeing to be bound by the
9 * terms of this license.
10 *
11 * You must not remove this notice, or any other, from this software.
12 */
13
14#ifndef _MINIZ_CONFIG_H
15#define _MINIZ_CONFIG_H
16
17/*
18 * miniz used only for crc32 calculation
19 */
20#define MINIZ_NO_STDIO
21#define MINIZ_NO_TIME
22#define MINIZ_NO_ARCHIVE_APIS
23#define MINIZ_NO_ARCHIVE_WRITING_APIS
24#define MINIZ_NO_ZLIB_APIS
25#define MINIZ_NO_MALLOC
26#ifdef ROCKBOX
27# define MINIZ_NO_ASSERT
28# ifndef SIMULATOR
29# define MINIZ_X86_OR_X64_CPU 0
30# define MINIZ_HAS_64BIT_REGISTERS 0
31# define TINFL_USE_64BIT_BITBUF 0
32# define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0
33# endif /* ndef SIMULATOR */
34#endif
35
36#endif /* ndef _MINIZ_CONFIG_H */
37
38/* eof */
diff --git a/apps/plugins/xrick/system/rockboxcodes.h b/apps/plugins/xrick/system/rockboxcodes.h
new file mode 100644
index 0000000000..ca56c338b6
--- /dev/null
+++ b/apps/plugins/xrick/system/rockboxcodes.h
@@ -0,0 +1,110 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#ifndef _ROCKBOXCODES_H
26#define _ROCKBOXCODES_H
27
28/* keypad mappings */
29#include "plugin.h"
30
31#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
32 (CONFIG_KEYPAD == IRIVER_H300_PAD)
33#define XRICK_BTN_UP BUTTON_UP | BUTTON_REC
34#define XRICK_BTN_DOWN BUTTON_DOWN | BUTTON_MODE
35#define XRICK_BTN_LEFT BUTTON_LEFT
36#define XRICK_BTN_RIGHT BUTTON_RIGHT
37#define XRICK_BTN_FIRE BUTTON_ON
38#define XRICK_BTN_PAUSE BUTTON_SELECT
39#define XRICK_BTN_MENU BUTTON_OFF
40
41#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
42#define XRICK_BTN_MENU BUTTON_POWER
43#define XRICK_BTN_FIRE BUTTON_PLAY
44#define XRICK_BTN_PAUSE BUTTON_REW
45#define XRICK_BTN_UP BUTTON_SCROLL_UP
46#define XRICK_BTN_DOWN BUTTON_SCROLL_DOWN
47#define XRICK_BTN_LEFT BUTTON_LEFT
48#define XRICK_BTN_RIGHT BUTTON_RIGHT
49
50#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || \
51 (CONFIG_KEYPAD == IPOD_3G_PAD) || \
52 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
53#define XRICK_BTN_UP BUTTON_MENU
54#define XRICK_BTN_DOWN BUTTON_PLAY
55#define XRICK_BTN_LEFT BUTTON_LEFT
56#define XRICK_BTN_RIGHT BUTTON_RIGHT
57#define XRICK_BTN_FIRE BUTTON_SELECT
58#define XRICK_BTN_PAUSE BUTTON_SCROLL_BACK
59#define XRICK_BTN_MENU BUTTON_SCROLL_FWD
60
61#elif (CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD)
62#define XRICK_BTN_UP BUTTON_UP
63#define XRICK_BTN_UPLEFT BUTTON_BACK
64#define XRICK_BTN_UPRIGHT BUTTON_PLAYPAUSE
65#define XRICK_BTN_DOWN BUTTON_DOWN
66#define XRICK_BTN_DOWNLEFT BUTTON_BOTTOMLEFT
67#define XRICK_BTN_DOWNRIGHT BUTTON_BOTTOMRIGHT
68#define XRICK_BTN_LEFT BUTTON_LEFT
69#define XRICK_BTN_RIGHT BUTTON_RIGHT
70#define XRICK_BTN_FIRE BUTTON_VOL_DOWN
71#define XRICK_BTN_PAUSE BUTTON_VOL_UP
72#define XRICK_BTN_MENU BUTTON_POWER
73
74#elif (CONFIG_KEYPAD == SAMSUNG_YH92X_PAD)
75#define XRICK_BTN_UP BUTTON_UP
76#define XRICK_BTN_DOWN BUTTON_DOWN
77#define XRICK_BTN_LEFT BUTTON_LEFT
78#define XRICK_BTN_RIGHT BUTTON_RIGHT
79#define XRICK_BTN_FIRE BUTTON_PLAY
80#define XRICK_BTN_PAUSE BUTTON_FFWD
81#define XRICK_BTN_MENU BUTTON_REW
82
83#elif (CONFIG_KEYPAD == SAMSUNG_YH820_PAD)
84#define XRICK_BTN_UP BUTTON_UP
85#define XRICK_BTN_DOWN BUTTON_DOWN
86#define XRICK_BTN_LEFT BUTTON_LEFT
87#define XRICK_BTN_RIGHT BUTTON_RIGHT
88#define XRICK_BTN_FIRE BUTTON_PLAY
89#define XRICK_BTN_PAUSE BUTTON_FFWD
90#define XRICK_BTN_MENU BUTTON_REW
91
92/* place other keypad mappings here
93#elif CONFIG_KEYPAD ==...
94#define XRICK_BTN...
95*/
96
97#else
98# include "lib/pluginlib_actions.h"
99#define XRICK_BTN_UP PLA_UP
100#define XRICK_BTN_DOWN PLA_DOWN
101#define XRICK_BTN_LEFT PLA_LEFT
102#define XRICK_BTN_RIGHT PLA_RIGHT
103#define XRICK_BTN_FIRE PLA_SELECT
104#define XRICK_BTN_PAUSE PLA_CANCEL
105#define XRICK_BTN_MENU PLA_EXIT
106#endif
107
108#endif /* ndef _ROCKBOXCODES_H */
109
110/* eof */
diff --git a/apps/plugins/xrick/system/sysarg_rockbox.c b/apps/plugins/xrick/system/sysarg_rockbox.c
new file mode 100644
index 0000000000..fa502ff4b0
--- /dev/null
+++ b/apps/plugins/xrick/system/sysarg_rockbox.c
@@ -0,0 +1,49 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27/*
28 * globals
29 */
30int sysarg_args_period = 0; /* time between each frame, in milliseconds. The default is 40. */
31int sysarg_args_map = 0;
32int sysarg_args_submap = 0;
33bool sysarg_args_nosound = false;
34const char *sysarg_args_data = NULL;
35
36/*
37 * Read and process arguments
38 */
39bool sysarg_init(int argc/*unused*/, char **argv)
40{
41 (void)argc;
42
43 /* note: "*argv" is truly a "const *" */
44 sysarg_args_data = *argv;
45
46 return true;
47}
48
49/* eof */
diff --git a/apps/plugins/xrick/system/sysevt_rockbox.c b/apps/plugins/xrick/system/sysevt_rockbox.c
new file mode 100644
index 0000000000..f5314712e8
--- /dev/null
+++ b/apps/plugins/xrick/system/sysevt_rockbox.c
@@ -0,0 +1,156 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27#include "xrick/config.h"
28#include "xrick/control.h"
29#include "xrick/game.h"
30#include "xrick/system/sysmenu_rockbox.h"
31#include "xrick/system/rockboxcodes.h"
32
33/*
34 * Helper function to set/clear controls according to key press
35 */
36static inline void checkKey(int key, unsigned button, control_t control)
37{
38 if (key & button)
39 {
40 control_set(control);
41 }
42 else
43 {
44 control_clear(control);
45 }
46}
47
48/*
49 * Process events, if any, then return
50 */
51void sysevt_poll(void)
52{
53 static int previousKey, currentKey;
54
55 /* this is because "Restart Game" is handled via menu */
56 if (control_test(Control_END))
57 {
58 control_clear(Control_END);
59 }
60
61 for (;;)
62 {
63 /* check for USB connection */
64 if ((rb->default_event_handler(rb->button_get(false)) == SYS_USB_CONNECTED)
65#if defined(HAS_BUTTON_HOLD)
66 || rb->button_hold()
67#endif
68 )
69 {
70 sysmenu_exec();
71 }
72
73 currentKey = rb->button_status();
74 if (currentKey != previousKey)
75 {
76 break;
77 }
78 else if (game_waitevt)
79 {
80 rb->yield();
81 }
82 else /* (currentKey == previousKey) && !game_waitevt */
83 {
84 return;
85 }
86 }
87
88#ifdef XRICK_BTN_MENU
89 if (currentKey & XRICK_BTN_MENU)
90 {
91 sysmenu_exec();
92 }
93#endif
94
95#ifdef XRICK_BTN_PAUSE
96 checkKey(currentKey, XRICK_BTN_PAUSE, Control_PAUSE);
97#endif
98
99 checkKey(currentKey, XRICK_BTN_UP, Control_UP);
100
101 checkKey(currentKey, XRICK_BTN_DOWN, Control_DOWN);
102
103 checkKey(currentKey, XRICK_BTN_LEFT, Control_LEFT);
104
105 checkKey(currentKey, XRICK_BTN_RIGHT, Control_RIGHT);
106
107 checkKey(currentKey, XRICK_BTN_FIRE, Control_FIRE);
108
109#ifdef XRICK_BTN_UPLEFT
110 if (!control_test(Control_UP | Control_LEFT))
111 {
112 checkKey(currentKey, XRICK_BTN_UPLEFT, Control_UP | Control_LEFT);
113 }
114#endif /* XRICK_BTN_UPLEFT */
115
116#ifdef XRICK_BTN_UPRIGHT
117 if (!control_test(Control_UP | Control_RIGHT))
118 {
119 checkKey(currentKey, XRICK_BTN_UPRIGHT, Control_UP | Control_RIGHT);
120 }
121#endif /* XRICK_BTN_UPRIGHT */
122
123#ifdef XRICK_BTN_DOWNLEFT
124 if (!control_test(Control_DOWN | Control_LEFT))
125 {
126 checkKey(currentKey, XRICK_BTN_DOWNLEFT, Control_DOWN | Control_LEFT);
127 }
128#endif /* XRICK_BTN_DOWNLEFT */
129
130#ifdef XRICK_BTN_DOWNRIGHT
131 if (!control_test(Control_DOWN | Control_RIGHT))
132 {
133 checkKey(currentKey, XRICK_BTN_DOWNRIGHT, Control_DOWN | Control_RIGHT);
134 }
135#endif /* XRICK_BTN_DOWNRIGHT */
136
137 previousKey = currentKey;
138}
139
140/*
141 * Wait for an event, then process it and return
142 */
143void sysevt_wait(void)
144{
145#ifdef HAVE_ADJUSTABLE_CPU_FREQ
146 rb->cpu_boost(false);
147#endif
148
149 sysevt_poll(); /* sysevt_poll deals with blocking case as well */
150
151#ifdef HAVE_ADJUSTABLE_CPU_FREQ
152 rb->cpu_boost(true);
153#endif
154}
155
156/* eof */
diff --git a/apps/plugins/xrick/system/sysfile_rockbox.c b/apps/plugins/xrick/system/sysfile_rockbox.c
new file mode 100644
index 0000000000..72227d5301
--- /dev/null
+++ b/apps/plugins/xrick/system/sysfile_rockbox.c
@@ -0,0 +1,122 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27#include "xrick/config.h"
28#include "xrick/util.h"
29
30#include "plugin.h"
31
32#define XRICK_GAME_DIR ROCKBOX_DIR "/xrick/"
33
34/*
35 * Global variables
36 */
37const char *sysfile_defaultPath = XRICK_GAME_DIR;
38
39/*
40 * Local variables
41 */
42static char *rootPath = NULL;
43
44/*
45 *
46 */
47bool sysfile_setRootPath(const char *name)
48{
49 rootPath = u_strdup(name);
50 return (rootPath != NULL);
51}
52
53/*
54 *
55 */
56void sysfile_clearRootPath()
57{
58 sysmem_pop(rootPath);
59 rootPath = NULL;
60}
61
62/*
63 * Open a data file.
64 */
65file_t sysfile_open(const char *name)
66{
67 int fd;
68
69 size_t fullPathLength = rb->strlen(rootPath) + rb->strlen(name) + 2;
70 char *fullPath = sysmem_push(fullPathLength);
71 if (!fullPath)
72 {
73 return NULL;
74 }
75 rb->snprintf(fullPath, fullPathLength, "%s/%s", rootPath, name);
76 fd = rb->open(fullPath, O_RDONLY);
77 sysmem_pop(fullPath);
78
79 /*
80 * note: I've never seen zero/NULL being used as a file descriptor under Rockbox.
81 * Putting a check here in case this will ever happen (will need a fix).
82 */
83 if (fd == 0)
84 {
85 sys_error("(file) unsupported file descriptor (zero/NULL) being used");
86 }
87 if (fd < 0)
88 {
89 return NULL;
90 }
91
92 return (file_t)fd;
93}
94
95/*
96 * Read a file within a data archive.
97 */
98int sysfile_read(file_t file, void *buf, size_t size, size_t count)
99{
100 int fd = (int)file;
101 return (rb->read(fd, buf, size * count) / size);
102}
103
104/*
105 * Seek.
106 */
107int sysfile_seek(file_t file, long offset, int origin)
108{
109 int fd = (int)file;
110 return rb->lseek(fd, offset, origin);
111}
112
113/*
114 * Close a file within a data archive.
115 */
116void sysfile_close(file_t file)
117{
118 int fd = (int)file;
119 rb->close(fd);
120}
121
122/* eof */
diff --git a/apps/plugins/xrick/system/sysmem_rockbox.c b/apps/plugins/xrick/system/sysmem_rockbox.c
new file mode 100644
index 0000000000..06a683a463
--- /dev/null
+++ b/apps/plugins/xrick/system/sysmem_rockbox.c
@@ -0,0 +1,156 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27#include "xrick/debug.h"
28
29#include "plugin.h"
30
31/*
32 * Local variables
33 */
34enum
35{
36 ALIGNMENT = sizeof(void*) /* this is more of an educated guess; might want to adjust for your specific architecture */
37};
38static U8 * stackBuffer;
39static U8 * stackTop;
40static size_t stackSize;
41static size_t stackMaxSize;
42static bool isMemoryInitialised = false;
43IFDEBUG_MEMORY( static size_t maxUsedMemory = 0; );
44
45/*
46 * Initialise memory stack
47 */
48bool sysmem_init(void)
49{
50 if (isMemoryInitialised)
51 {
52 return true;
53 }
54
55 if (rb->audio_status())
56 {
57 /* Playback must be stopped the entire time the sound buffer is used.*/
58 rb->audio_stop();
59 }
60
61 stackBuffer = rb->plugin_get_audio_buffer(&stackMaxSize);
62 stackTop = stackBuffer;
63 stackSize = 0;
64 isMemoryInitialised = true;
65 return true;
66}
67
68/*
69 * Cleanup memory stack
70 */
71void sysmem_shutdown(void)
72{
73 if (!isMemoryInitialised)
74 {
75 return;
76 }
77
78 if (stackTop != stackBuffer || stackSize != 0)
79 {
80 sys_error("(memory) improper deallocation detected");
81 }
82
83 IFDEBUG_MEMORY(
84 sys_printf("xrick/memory: max memory usage was %u bytes\n", maxUsedMemory);
85 );
86
87 isMemoryInitialised = false;
88}
89
90/*
91 * Allocate a memory-aligned block on top of the memory stack
92 */
93void *sysmem_push(size_t size)
94{
95 uintptr_t alignedPtr;
96 size_t * allocatedSizePtr;
97
98 size_t neededSize = sizeof(size_t) + size + (ALIGNMENT - 1);
99 if (stackSize + neededSize > stackMaxSize)
100 {
101 sys_error("(memory) tried to allocate a block when memory full");
102 return NULL;
103 }
104
105 alignedPtr = (((uintptr_t)stackTop) + sizeof(size_t) + ALIGNMENT) & ~((uintptr_t)(ALIGNMENT - 1));
106
107 allocatedSizePtr = (size_t *)(alignedPtr);
108 allocatedSizePtr[-1] = neededSize;
109
110 stackTop += neededSize;
111 stackSize += neededSize;
112
113 IFDEBUG_MEMORY(
114 sys_printf("xrick/memory: allocated %u bytes\n", neededSize);
115 if (stackSize > maxUsedMemory) maxUsedMemory = stackSize;
116 );
117
118 return (void *)alignedPtr;
119}
120
121/*
122 * Release block from the top of the memory stack
123 */
124void sysmem_pop(void * alignedPtr)
125{
126 size_t allocatedSize;
127
128 if (!alignedPtr)
129 {
130 return;
131 }
132
133 if (stackSize == 0)
134 {
135 sys_error("(memory) tried to release a block when memory empty");
136 return;
137 }
138
139 allocatedSize = ((size_t *)(alignedPtr))[-1];
140 stackTop -= allocatedSize;
141 stackSize -= allocatedSize;
142
143 IFDEBUG_MEMORY(
144 if ((uintptr_t)alignedPtr != ((((uintptr_t)stackTop) + sizeof(size_t) + ALIGNMENT) & ~((uintptr_t)(ALIGNMENT - 1))))
145 {
146 sys_error("(memory) tried to release a wrong block");
147 return;
148 }
149 );
150
151 IFDEBUG_MEMORY(
152 sys_printf("xrick/memory: released %u bytes\n", allocatedSize);
153 );
154}
155
156/* eof */
diff --git a/apps/plugins/xrick/system/sysmenu_rockbox.c b/apps/plugins/xrick/system/sysmenu_rockbox.c
new file mode 100644
index 0000000000..fb80881749
--- /dev/null
+++ b/apps/plugins/xrick/system/sysmenu_rockbox.c
@@ -0,0 +1,200 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/sysmenu_rockbox.h"
26
27#include "xrick/config.h"
28#include "xrick/control.h"
29#include "xrick/draw.h"
30#include "xrick/game.h"
31#include "xrick/system/system.h"
32#include "xrick/system/syssnd_rockbox.h"
33
34#include "plugin.h"
35#ifndef HAVE_LCD_COLOR
36#include "lib/grey.h"
37#endif
38
39#ifdef HAVE_LCD_COLOR
40static fb_data *lcd_fb=NULL;
41#endif
42
43#ifdef ENABLE_CHEATS
44/*
45 * Cheat settings menu
46 */
47static char * sysmenu_cheatItemText(int selected_item, void *data, char *buffer, size_t buffer_len)
48{
49 (void)selected_item;
50 cheat_t cheat = (cheat_t)data;
51 (void)buffer;
52 (void)buffer_len;
53 char * messages[] =
54 {
55 "Disable Unlimited Lives/Ammo Mode",
56 "Enable Unlimited Lives/Ammo Mode",
57 "Disable Never Die Mode",
58 "Enable Never Die Mode",
59 "Disable Expose Mode",
60 "Enable Expose Mode"
61 };
62
63 switch (cheat)
64 {
65 case Cheat_UNLIMITED_ALL:
66 {
67 return game_cheat1? messages[0] : messages[1];
68 }
69 case Cheat_NEVER_DIE:
70 {
71 return game_cheat2? messages[2] : messages[3];
72 }
73 case Cheat_EXPOSE:
74 {
75 return game_cheat3? messages[4] : messages[5];
76 }
77 default: break;
78 }
79 return "";
80}
81
82/*
83 * Callback invoked by cheat menu item
84 */
85static int sysmenu_doToggleCheat(void *param)
86{
87 cheat_t cheat = (cheat_t)param;
88 game_toggleCheat(cheat);
89 return 0;
90}
91
92MENUITEM_FUNCTION_DYNTEXT(sysmenu_unlimitedAllItem, MENU_FUNC_USEPARAM, sysmenu_doToggleCheat,
93 sysmenu_cheatItemText, NULL, (void *)Cheat_UNLIMITED_ALL,
94 NULL, Icon_NOICON);
95
96MENUITEM_FUNCTION_DYNTEXT(sysmenu_neverDieItem, MENU_FUNC_USEPARAM, sysmenu_doToggleCheat,
97 sysmenu_cheatItemText, NULL, (void *)Cheat_NEVER_DIE,
98 NULL, Icon_NOICON);
99
100MENUITEM_FUNCTION_DYNTEXT(sysmenu_exposeItem, MENU_FUNC_USEPARAM, sysmenu_doToggleCheat,
101 sysmenu_cheatItemText, NULL, (void *)Cheat_EXPOSE,
102 NULL, Icon_NOICON);
103
104MAKE_MENU(sysmenu_cheatItems, "Cheat Settings", NULL, Icon_NOICON,
105 &sysmenu_unlimitedAllItem, &sysmenu_neverDieItem, &sysmenu_exposeItem);
106
107#endif /* ENABLE_CHEATS */
108
109/*
110 * Display main menu
111 */
112void sysmenu_exec(void)
113{
114 int result;
115 bool done;
116
117 enum
118 {
119 Menu_RESUME,
120 Menu_RESTART,
121#ifdef ENABLE_CHEATS
122 Menu_CHEAT_SETTINGS,
123#endif
124 Menu_QUIT
125 };
126
127 MENUITEM_STRINGLIST(sysmenu_mainItems, "xrick Menu", NULL,
128 "Resume Game",
129 "Restart Game",
130#ifdef ENABLE_CHEATS
131 "Cheat Settings",
132#endif
133 ID2P(LANG_MENU_QUIT));
134
135#ifdef ENABLE_SOUND
136 syssnd_pauseAll(true);
137#endif
138
139#ifndef HAVE_LCD_COLOR
140 grey_show(false);
141#endif
142
143 done = false;
144 do
145 {
146 rb->button_clear_queue();
147
148 result = rb->do_menu(&sysmenu_mainItems, NULL, NULL, false);
149 switch(result)
150 {
151 case Menu_RESUME:
152 {
153 done = true;
154 break;
155 }
156 case Menu_RESTART:
157 {
158 control_set(Control_END);
159 done = true;
160 break;
161 }
162#ifdef ENABLE_CHEATS
163 case Menu_CHEAT_SETTINGS:
164 {
165 rb->do_menu(&sysmenu_cheatItems, NULL, NULL, false);
166 break;
167 }
168#endif
169 case Menu_QUIT:
170 {
171 control_set(Control_EXIT);
172 done = true;
173 break;
174 }
175 default: break;
176 }
177 } while (!done);
178
179#ifdef HAVE_LCD_COLOR
180 if (!(control_test(Control_EXIT)))
181 {
182 if(!lcd_fb)
183 {
184 struct viewport *vp_main = rb->lcd_set_viewport(NULL);
185 lcd_fb = vp_main->buffer->fb_ptr;
186 }
187 rb->memset(lcd_fb, 0, sizeof(fb_data) * LCD_WIDTH * LCD_HEIGHT);
188 sysvid_update(&draw_SCREENRECT);
189 rb->lcd_update();
190 }
191#else
192 grey_show(true);
193#endif
194
195#ifdef ENABLE_SOUND
196 syssnd_pauseAll(false);
197#endif
198}
199
200/* eof */
diff --git a/apps/plugins/xrick/system/sysmenu_rockbox.h b/apps/plugins/xrick/system/sysmenu_rockbox.h
new file mode 100644
index 0000000000..fcd13606fa
--- /dev/null
+++ b/apps/plugins/xrick/system/sysmenu_rockbox.h
@@ -0,0 +1,32 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#ifndef _SYSMENU_ROCKBOX_H
26#define _SYSMENU_ROCKBOX_H
27
28extern void sysmenu_exec(void);
29
30#endif /* ndef _SYSMENU_ROCKBOX_H */
31
32/* eof */
diff --git a/apps/plugins/xrick/system/syssnd_rockbox.c b/apps/plugins/xrick/system/syssnd_rockbox.c
new file mode 100644
index 0000000000..97ed5474f1
--- /dev/null
+++ b/apps/plugins/xrick/system/syssnd_rockbox.c
@@ -0,0 +1,483 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/config.h"
26
27#ifdef ENABLE_SOUND
28
29#include "xrick/system/system.h"
30
31#include "xrick/game.h"
32#include "xrick/debug.h"
33#include "xrick/system/syssnd_rockbox.h"
34
35#include "plugin.h"
36
37/*
38 * Global variables
39 */
40const U8 syssnd_period = 20;
41
42/*
43 * Local variables
44 */
45enum
46{
47 SYSSND_MIX_CHANNELS = 5,
48 SYSSND_MIX_SAMPLES = 1024, /* try changing this value if sound mixing is too slow or choppy */
49 SYSSND_SOURCE_SAMPLES = SYSSND_MIX_SAMPLES / 2
50};
51
52/* channels to be mixed */
53static channel_t channels[SYSSND_MIX_CHANNELS];
54/* buffer used to mix sounds sent to pcm playback, stores 16b stereo 44Khz audio samples */
55enum { AUDIO_BUFFER_COUNT = 4 };
56typedef struct
57{
58 U32 data[SYSSND_MIX_SAMPLES];
59 size_t length; /* in 8 bit mono samples */
60} mix_buffer_t;
61static mix_buffer_t mixBuffers[AUDIO_BUFFER_COUNT];
62static size_t writeIndex;
63static size_t readIndex;
64static size_t fillCount;
65static bool isAudioPlaying;
66static bool isAudioInitialised = false;
67
68/*
69 * Prototypes
70 */
71static void endChannel(size_t c);
72static void get_more(const void **start, size_t *size);
73
74/*
75 * Deactivate channel
76 */
77static void endChannel(size_t c)
78{
79 channels[c].loop = 0;
80 channels[c].sound = NULL;
81}
82
83/*
84 * Audio callback
85 */
86static void get_more(const void **start, size_t *size)
87{
88 if (fillCount > 0)
89 {
90 /* Store output data address and size. */
91 *start = mixBuffers[readIndex].data;
92 *size = mixBuffers[readIndex].length * 8;
93
94 /* Free this part of output buffer. */
95 mixBuffers[readIndex].length = 0;
96
97 /* Advance to the next part of output buffer. */
98 readIndex = (readIndex + 1) & (AUDIO_BUFFER_COUNT - 1);
99 fillCount--;
100 }
101 else
102 {
103 /* Nothing to play. */
104 isAudioPlaying = false;
105 }
106}
107
108/*
109 * Mix audio samples and fill playback buffer
110 */
111void syssnd_update(void)
112{
113 if (!isAudioInitialised)
114 {
115 return;
116 }
117
118 for (;;)
119 {
120 size_t c;
121 size_t sampleOffset;
122 size_t maxSampleCount;
123 bool isFirstSound;
124 U8 *sourceBuf, *sourceBufEnd;
125 U32 *destBuf;
126
127 /* Cancel if whole buffer filled. */
128 if (fillCount >= (AUDIO_BUFFER_COUNT - 1))
129 {
130 return;
131 }
132
133 maxSampleCount = 0;
134
135 sampleOffset = mixBuffers[writeIndex].length;
136 destBuf = mixBuffers[writeIndex].data + sampleOffset * 2;
137
138 isFirstSound = true;
139 for (c = 0; c < SYSSND_MIX_CHANNELS ; ++c)
140 {
141 U32 * mixBuffer;
142 size_t sampleCount;
143 channel_t * channel = &channels[c];
144
145 if (!channel->sound /* no sound to play on this channel */
146 || (channel->loop == 0)) /* channel is inactive */
147 {
148 continue;
149 }
150
151 if (isFirstSound)
152 {
153 /* clear mixing buffer */
154 rb->memset(destBuf, 0, (SYSSND_MIX_SAMPLES - (sampleOffset * 2)) * sizeof(U32));
155 isFirstSound = false;
156 }
157
158 sampleCount = MIN(SYSSND_SOURCE_SAMPLES - sampleOffset, channel->len);
159 if (maxSampleCount < sampleCount)
160 {
161 maxSampleCount = sampleCount;
162 }
163
164 /* mix sound samples */
165 mixBuffer = destBuf;
166 sourceBuf = channel->buf;
167 sourceBufEnd = channel->buf + sampleCount;
168 while (sourceBuf < sourceBufEnd)
169 {
170 /* Convert from unsigned 8 bit mono 22khz to signed 16 bit stereo 44khz */
171 const int sourceSample = *sourceBuf++;
172 int monoSample = (sourceSample - 0x80) << 8;
173 U32 stereoSample = *mixBuffer;
174 monoSample += (S32)(stereoSample) >> 16;
175 if (monoSample >= 0x8000)
176 {
177 monoSample = 0x7FFF;
178 }
179 else if (monoSample < -0x8000)
180 {
181 monoSample = -0x8000;
182 }
183 stereoSample = (U16)monoSample | ((U16)monoSample << 16);
184 *mixBuffer++ = stereoSample;
185 *mixBuffer++ = stereoSample;
186 }
187 channel->buf = sourceBufEnd;
188
189 channel->len -= sampleCount;
190 if (channel->len == 0) /* ending ? */
191 {
192 if (channel->loop > 0)
193 {
194 channel->loop--;
195 }
196 if (channel->loop)
197 {
198 /* just loop */
199 IFDEBUG_AUDIO2(sys_printf("xrick/audio: channel %d - loop\n", c););
200 channel->buf = channel->sound->buf;
201 channel->len = channel->sound->len;
202 }
203 else
204 {
205 /* end for real */
206 IFDEBUG_AUDIO2(sys_printf("xrick/audio: channel %d - end\n", c););
207 endChannel(c);
208 }
209 }
210 }
211
212 if (maxSampleCount == 0)
213 {
214 return;
215 }
216
217 mixBuffers[writeIndex].length += maxSampleCount;
218
219 /* Advance one part of audio buffer. */
220 writeIndex = (writeIndex + 1) & (AUDIO_BUFFER_COUNT - 1);
221 fillCount++;
222
223 if (!isAudioPlaying && fillCount > 0)
224 {
225 rb->pcm_play_data(&get_more, NULL, NULL, 0);
226 isAudioPlaying = true;
227 }
228 }
229}
230
231/*
232 * Initialise audio
233 */
234bool syssnd_init(void)
235{
236 if (isAudioInitialised)
237 {
238 return true;
239 }
240
241 IFDEBUG_AUDIO(sys_printf("xrick/audio: start\n"););
242
243 rb->talk_disable(true);
244
245 /* Stop playback to reconfigure audio settings and acquire audio buffer */
246 rb->mixer_channel_stop(PCM_MIXER_CHAN_PLAYBACK);
247
248#if INPUT_SRC_CAPS != 0
249 /* Select playback */
250 rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
251 rb->audio_set_output_source(AUDIO_SRC_PLAYBACK);
252#endif
253
254 rb->pcm_set_frequency(HW_FREQ_44);
255 rb->pcm_apply_settings();
256
257 rb->memset(channels, 0, sizeof(channels));
258 rb->memset(mixBuffers, 0, sizeof(mixBuffers));
259
260 writeIndex = 0;
261 readIndex = 0;
262 fillCount = 0;
263 isAudioPlaying = false;
264
265 isAudioInitialised = true;
266 IFDEBUG_AUDIO(sys_printf("xrick/audio: ready\n"););
267 return true;
268}
269
270/*
271 * Shutdown
272 */
273void syssnd_shutdown(void)
274{
275 if (!isAudioInitialised)
276 {
277 return;
278 }
279
280 /* Stop playback. */
281 rb->pcm_play_stop();
282
283 /* Reset playing status. */
284 isAudioPlaying = false;
285
286 /* Restore default sampling rate. */
287 rb->pcm_set_frequency(HW_SAMPR_DEFAULT);
288 rb->pcm_apply_settings();
289
290 rb->talk_disable(false);
291
292 isAudioInitialised = false;
293 IFDEBUG_AUDIO(sys_printf("xrick/audio: stop\n"););
294}
295
296/*
297 * Play a sound
298 *
299 * loop: number of times the sound should be played, -1 to loop forever
300 *
301 * NOTE if sound is already playing, simply reset it (i.e. can not have
302 * twice the same sound playing -- tends to become noisy when too many
303 * bad guys die at the same time).
304 */
305void syssnd_play(sound_t *sound, S8 loop)
306{
307 size_t c;
308
309 if (!isAudioInitialised || !sound)
310 {
311 return;
312 }
313
314 c = 0;
315 while (channels[c].sound != sound &&
316 channels[c].loop != 0 &&
317 c < SYSSND_MIX_CHANNELS)
318 {
319 c++;
320 }
321 if (c >= SYSSND_MIX_CHANNELS)
322 {
323 return;
324 }
325
326 if (!sound->buf)
327 {
328 syssnd_load(sound);
329 if (!sound->buf)
330 {
331 sys_error("(audio) can not load %s", sound->name);
332 return;
333 }
334 }
335
336 IFDEBUG_AUDIO(
337 if (channels[c].sound == sound)
338 {
339 sys_printf("xrick/audio: already playing %s on channel %d - resetting\n",
340 sound->name, c);
341 }
342 else
343 {
344 sys_printf("xrick/audio: playing %s on channel %d\n", sound->name, c);
345 }
346 );
347
348 channels[c].loop = loop;
349 channels[c].sound = sound;
350 channels[c].buf = sound->buf;
351 channels[c].len = sound->len;
352}
353
354/*
355 * Pause all sounds
356 */
357void syssnd_pauseAll(bool pause)
358{
359 if (!isAudioInitialised)
360 {
361 return;
362 }
363
364 rb->pcm_play_lock();
365 rb->mixer_channel_play_pause(PCM_MIXER_CHAN_PLAYBACK, !pause);
366 rb->pcm_play_unlock();
367}
368
369/*
370 * Stop a sound
371 */
372void syssnd_stop(sound_t *sound)
373{
374 size_t c;
375
376 if (!isAudioInitialised || !sound)
377 {
378 return;
379 }
380
381 for (c = 0; c < SYSSND_MIX_CHANNELS; c++)
382 {
383 if (channels[c].sound == sound)
384 {
385 endChannel(c);
386 }
387 }
388}
389
390/*
391 * Stops all channels.
392 */
393void syssnd_stopAll(void)
394{
395 size_t c;
396
397 if (!isAudioInitialised)
398 {
399 return;
400 }
401
402 for (c = 0; c < SYSSND_MIX_CHANNELS; c++)
403 {
404 if (channels[c].sound)
405 {
406 endChannel(c);
407 }
408 }
409}
410
411/*
412 * Load a sound.
413 */
414void syssnd_load(sound_t *sound)
415{
416 int bytesRead;
417 file_t fp;
418 bool success;
419
420 if (!isAudioInitialised || !sound)
421 {
422 return;
423 }
424
425 success = false;
426 do
427 {
428 sound->buf = sysmem_push(sound->len);
429 if (!sound->buf)
430 {
431 sys_error("(audio) not enough memory for \"%s\", %d bytes needed", sound->name, sound->len);
432 break;
433 }
434
435 fp = sysfile_open(sound->name);
436 if (!fp)
437 {
438 sys_error("(audio) unable to open \"%s\"", sound->name);
439 break;
440 }
441
442 sysfile_seek(fp, sizeof(wave_header_t), SEEK_SET); /* skip WAVE header */
443
444 bytesRead = sysfile_read(fp, sound->buf, sound->len, 1);
445 sysfile_close(fp);
446 if (bytesRead != 1)
447 {
448 sys_error("(audio) unable to read from \"%s\"", sound->name);
449 break;
450 }
451
452 success = true;
453 } while (false);
454
455 if (!success)
456 {
457 sysmem_pop(sound->buf);
458 sound->buf = NULL;
459 sound->len = 0;
460 return;
461 }
462
463 IFDEBUG_AUDIO(sys_printf("xrick/audio: successfully loaded \"%s\"\n", sound->name););
464}
465
466/*
467 * Unload a sound.
468 */
469void syssnd_unload(sound_t *sound)
470{
471 if (!isAudioInitialised || !sound || !sound->buf)
472 {
473 return;
474 }
475
476 sysmem_pop(sound->buf);
477 sound->buf = NULL;
478 sound->len = 0;
479}
480
481#endif /* ENABLE_SOUND */
482
483/* eof */
diff --git a/apps/plugins/xrick/system/syssnd_rockbox.h b/apps/plugins/xrick/system/syssnd_rockbox.h
new file mode 100644
index 0000000000..41bd7d8454
--- /dev/null
+++ b/apps/plugins/xrick/system/syssnd_rockbox.h
@@ -0,0 +1,48 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#ifndef _SYSSND_ROCKBOX_H
26#define _SYSSND_ROCKBOX_H
27
28#include "xrick/config.h"
29
30#ifdef ENABLE_SOUND
31
32#include "xrick/system/system.h"
33
34typedef struct {
35 sound_t *sound;
36 U8 *buf;
37 U32 len;
38 S8 loop;
39} channel_t;
40
41extern void syssnd_load(sound_t *);
42extern void syssnd_unload(sound_t *);
43
44#endif /* ENABLE_SOUND */
45
46#endif /* ndef _SYSSND_ROCKBOX_H */
47
48/* eof */
diff --git a/apps/plugins/xrick/system/system.h b/apps/plugins/xrick/system/system.h
new file mode 100644
index 0000000000..d4dda3d5d4
--- /dev/null
+++ b/apps/plugins/xrick/system/system.h
@@ -0,0 +1,178 @@
1/*
2 * xrick/system/system.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _SYSTEM_H
17#define _SYSTEM_H
18
19/*
20 * Detect GCC
21 */
22#ifdef __GNUC__
23/*
24 * make POSIX functions available
25 */
26# ifndef _POSIX_SOURCE
27# define _POSIX_SOURCE
28# endif
29#endif
30
31/*
32 * Detect Microsoft Visual C
33 */
34#ifdef _MSC_VER
35/*
36 * FIXME disable "integral size mismatch in argument; conversion supplied" warning
37 * as long as the code has not been cleared -- there are so many of them...
38 */
39#pragma warning( disable : 4761 )
40#endif
41
42/*
43 * Detect Microsoft Windows
44 */
45#if !defined( __WIN32__ ) && ( defined( WIN32 ) || defined( _WIN32 ) )
46#define __WIN32__
47#endif
48
49#include "xrick/config.h"
50#include "xrick/rects.h"
51#include "xrick/data/img.h"
52#ifdef ENABLE_SOUND
53#include "xrick/data/sounds.h"
54#endif
55
56#include <stddef.h> /* size_t */
57#include <sys/types.h> /* off_t */
58
59/*
60 * main section
61 */
62extern bool sys_init(int, char **);
63extern void sys_shutdown(void);
64extern void sys_error(const char *, ...);
65extern void sys_printf(const char *, ...);
66extern void sys_snprintf(char *, size_t, const char *, ...);
67extern size_t sys_strlen(const char *);
68extern U32 sys_gettime(void);
69extern void sys_yield(void);
70extern bool sys_cacheData(void);
71extern void sys_uncacheData(void);
72
73/*
74 * memory section
75 */
76extern bool sysmem_init(void);
77extern void sysmem_shutdown(void);
78extern void *sysmem_push(size_t);
79extern void sysmem_pop(void *);
80
81/*
82 * video section
83 */
84#define SYSVID_ZOOM 2
85#define SYSVID_MAXZOOM 4
86#define SYSVID_WIDTH 320
87#define SYSVID_HEIGHT 200
88
89extern U8 *sysvid_fb; /* frame buffer */
90
91extern bool sysvid_init(void);
92extern void sysvid_shutdown(void);
93extern void sysvid_update(const rect_t *);
94extern void sysvid_clear(void);
95extern void sysvid_zoom(S8);
96extern void sysvid_toggleFullscreen(void);
97extern void sysvid_setGamePalette(void);
98extern void sysvid_setPalette(img_color_t *, U16);
99
100/*
101 * file management section
102 */
103typedef void *file_t;
104
105extern const char *sysfile_defaultPath;
106
107extern bool sysfile_setRootPath(const char *);
108extern void sysfile_clearRootPath(void);
109
110extern file_t sysfile_open(const char *);
111extern int sysfile_seek(file_t file, long offset, int origin);
112extern int sysfile_tell(file_t);
113extern off_t sysfile_size(file_t);
114extern int sysfile_read(file_t, void *, size_t, size_t);
115extern void sysfile_close(file_t);
116
117/*
118 * events section
119 */
120extern void sysevt_poll(void);
121extern void sysevt_wait(void);
122
123/*
124 * keyboard section
125 */
126extern U8 syskbd_up;
127extern U8 syskbd_down;
128extern U8 syskbd_left;
129extern U8 syskbd_right;
130extern U8 syskbd_pause;
131extern U8 syskbd_end;
132extern U8 syskbd_xtra;
133extern U8 syskbd_fire;
134
135/*
136 * sound section
137 */
138#ifdef ENABLE_SOUND
139extern const U8 syssnd_period; /* time between each sound update, in millisecond */
140
141extern bool syssnd_init(void);
142extern void syssnd_shutdown(void);
143extern void syssnd_update(void);
144extern void syssnd_vol(S8);
145extern void syssnd_toggleMute(void);
146extern void syssnd_play(sound_t *, S8);
147extern void syssnd_pauseAll(bool);
148extern void syssnd_stop(sound_t *);
149extern void syssnd_stopAll(void);
150#endif /* ENABLE_ SOUND */
151
152/*
153 * args section
154 */
155extern int sysarg_args_period;
156extern int sysarg_args_map;
157extern int sysarg_args_submap;
158extern int sysarg_args_fullscreen;
159extern int sysarg_args_zoom;
160#ifdef ENABLE_SOUND
161extern bool sysarg_args_nosound;
162extern int sysarg_args_vol;
163#endif /* ENABLE_ SOUND */
164extern const char *sysarg_args_data;
165
166extern bool sysarg_init(int, char **);
167
168/*
169 * joystick section
170 */
171#ifdef ENABLE_JOYSTICK
172extern bool sysjoy_init(void);
173extern void sysjoy_shutdown(void);
174#endif
175
176#endif /* ndef _SYSTEM_H */
177
178/* eof */
diff --git a/apps/plugins/xrick/system/system_rockbox.c b/apps/plugins/xrick/system/system_rockbox.c
new file mode 100644
index 0000000000..3b5f96a4ed
--- /dev/null
+++ b/apps/plugins/xrick/system/system_rockbox.c
@@ -0,0 +1,262 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27#include "xrick/config.h"
28#ifdef ENABLE_SOUND
29#include "xrick/system/syssnd_rockbox.h"
30#endif
31
32#include "plugin.h"
33
34enum { LINE_LENGTH = 80 };
35
36/*
37* Error
38*/
39void sys_error(const char *err, ...)
40{
41 va_list argptr;
42 char s[LINE_LENGTH];
43
44 /* prepare message */
45 va_start(argptr, err);
46 rb->vsnprintf(s, sizeof(s), err, argptr);
47 va_end(argptr);
48
49 /* print error message */
50 rb->splashf(HZ*3, ID2P(LANG_ERROR_FORMATSTR), s);
51 DEBUGF("Error: %s\n", s);
52}
53
54/*
55* Print a message to standard output
56*/
57void sys_printf(const char *msg, ...)
58{
59 va_list argptr;
60 char s[LINE_LENGTH];
61
62 /* prepare message */
63 va_start(argptr, msg);
64 rb->vsnprintf(s, sizeof(s), msg, argptr);
65 va_end(argptr);
66
67 /* print message */
68 DEBUGF("%s",s);
69
70#ifdef ENABLE_SYSPRINTF_TO_SCREEN
71 {
72 static int currentYPos = 0;
73 size_t i;
74
75 /* Device LCDs display newlines funny. */
76 for(i = 0; s[i] != '\0'; ++i)
77 {
78 if(s[i] == '\n')
79 {
80 s[i] = ' ';
81 }
82 }
83
84 rb->lcd_putsxy(1, currentYPos, (unsigned char *)s);
85 rb->lcd_update();
86
87 currentYPos += 12;
88 if(currentYPos > LCD_HEIGHT-12)
89 {
90 currentYPos = 0;
91 rb->lcd_clear_display();
92 }
93 }
94#endif /* ENABLE_SYSPRINTF_TO_SCREEN */
95}
96
97/*
98* Print a message to string buffer
99*/
100void sys_snprintf(char *buf, size_t size, const char *msg, ...)
101{
102 va_list argptr;
103
104 va_start(argptr, msg);
105 rb->vsnprintf(buf, size, msg, argptr);
106 va_end(argptr);
107}
108
109/*
110* Returns string length
111*/
112size_t sys_strlen(const char * str)
113{
114 return rb->strlen(str);
115}
116
117/*
118* Return number of milliseconds elapsed since first call
119*/
120U32 sys_gettime(void)
121{
122 long ticks = *(rb->current_tick);
123 return (U32)((ticks * 1000) / HZ);
124}
125
126/*
127* Yield execution to another thread
128*/
129void sys_yield(void)
130{
131 rb->yield();
132}
133
134/*
135* Initialize system
136*/
137bool sys_init(int argc, char **argv)
138{
139#ifdef HAVE_ADJUSTABLE_CPU_FREQ
140 rb->cpu_boost(true);
141#endif
142
143 if (!sysarg_init(argc, argv))
144 {
145 return false;
146 }
147 if (!sysmem_init())
148 {
149 return false;
150 }
151 if (!sysvid_init())
152 {
153 return false;
154 }
155#ifdef ENABLE_SOUND
156 if (!sysarg_args_nosound && !syssnd_init())
157 {
158 return false;
159 }
160#endif
161 if (!sysfile_setRootPath(sysarg_args_data? sysarg_args_data : sysfile_defaultPath))
162 {
163 return false;
164 }
165 return true;
166}
167
168/*
169* Shutdown system
170*/
171void sys_shutdown(void)
172{
173 sysfile_clearRootPath();
174#ifdef ENABLE_SOUND
175 syssnd_shutdown();
176#endif
177 sysvid_shutdown();
178 sysmem_shutdown();
179
180#ifdef HAVE_ADJUSTABLE_CPU_FREQ
181 rb->cpu_boost(false);
182#endif
183}
184
185/*
186* Preload data before entering main loop
187*/
188bool sys_cacheData(void)
189{
190#ifdef ENABLE_SOUND
191 syssnd_load(soundGameover);
192 syssnd_load(soundSbonus2);
193 syssnd_load(soundBullet);
194 syssnd_load(soundBombshht);
195 syssnd_load(soundExplode);
196 syssnd_load(soundStick);
197 syssnd_load(soundWalk);
198 syssnd_load(soundCrawl);
199 syssnd_load(soundJump);
200 syssnd_load(soundPad);
201 syssnd_load(soundBox);
202 syssnd_load(soundBonus);
203 syssnd_load(soundSbonus1);
204 syssnd_load(soundDie);
205 syssnd_load(soundEntity[0]);
206 syssnd_load(soundEntity[1]);
207 syssnd_load(soundEntity[2]);
208 syssnd_load(soundEntity[3]);
209 syssnd_load(soundEntity[4]);
210 syssnd_load(soundEntity[5]);
211 syssnd_load(soundEntity[6]);
212 syssnd_load(soundEntity[7]);
213 syssnd_load(soundEntity[8]);
214 syssnd_load(soundTune0);
215 syssnd_load(soundTune1);
216 syssnd_load(soundTune2);
217 syssnd_load(soundTune3);
218 syssnd_load(soundTune4);
219 syssnd_load(soundTune5);
220#endif /* ENABLE_SOUND */
221 return true;
222}
223
224/*
225* Clear preloaded data before shutdown
226*/
227void sys_uncacheData(void)
228{
229#ifdef ENABLE_SOUND
230 syssnd_unload(soundTune5);
231 syssnd_unload(soundTune4);
232 syssnd_unload(soundTune3);
233 syssnd_unload(soundTune2);
234 syssnd_unload(soundTune1);
235 syssnd_unload(soundTune0);
236 syssnd_unload(soundEntity[8]);
237 syssnd_unload(soundEntity[7]);
238 syssnd_unload(soundEntity[6]);
239 syssnd_unload(soundEntity[5]);
240 syssnd_unload(soundEntity[4]);
241 syssnd_unload(soundEntity[3]);
242 syssnd_unload(soundEntity[2]);
243 syssnd_unload(soundEntity[1]);
244 syssnd_unload(soundEntity[0]);
245 syssnd_unload(soundDie);
246 syssnd_unload(soundSbonus1);
247 syssnd_unload(soundBonus);
248 syssnd_unload(soundBox);
249 syssnd_unload(soundPad);
250 syssnd_unload(soundJump);
251 syssnd_unload(soundCrawl);
252 syssnd_unload(soundWalk);
253 syssnd_unload(soundStick);
254 syssnd_unload(soundExplode);
255 syssnd_unload(soundBombshht);
256 syssnd_unload(soundBullet);
257 syssnd_unload(soundSbonus2);
258 syssnd_unload(soundGameover);
259#endif /* ENABLE_SOUND */
260}
261
262/* eof */
diff --git a/apps/plugins/xrick/system/sysvid_rockbox.c b/apps/plugins/xrick/system/sysvid_rockbox.c
new file mode 100644
index 0000000000..236bc87616
--- /dev/null
+++ b/apps/plugins/xrick/system/sysvid_rockbox.c
@@ -0,0 +1,402 @@
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Port of xrick, a Rick Dangerous clone, to Rockbox.
11 * See http://www.bigorno.net/xrick/
12 *
13 * Copyright (C) 2008-2014 Pierluigi Vicinanza
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25#include "xrick/system/system.h"
26
27#include "xrick/config.h"
28#include "xrick/draw.h"
29#include "xrick/game.h"
30#include "xrick/data/img.h"
31#include "xrick/debug.h"
32
33#include "plugin.h"
34#include "lib/helper.h"
35
36/*
37 * Global variables
38 */
39U8 *sysvid_fb = NULL; /* xRick generic 320x200 8bpp frame buffer */
40
41/*
42 * Local variables
43 */
44static fb_data palette[256] IBSS_ATTR;
45static bool isVideoInitialised = false;
46#ifndef HAVE_LCD_COLOR
47# include "lib/grey.h"
48GREY_INFO_STRUCT_IRAM
49static unsigned char greybuffer[LCD_HEIGHT * LCD_WIDTH] IBSS_ATTR; /* off screen buffer */
50static unsigned char *gbuf;
51# if LCD_PIXELFORMAT == HORIZONTAL_PACKING
52enum { GREYBUFSIZE = (((LCD_WIDTH+7)/8)*LCD_HEIGHT*16+200) };
53# else
54enum { GREYBUFSIZE = (LCD_WIDTH*((LCD_HEIGHT+7)/8)*16+200) };
55# endif
56#endif /* ndef HAVE_LCD_COLOR */
57
58static fb_data *lcd_fb = NULL;
59
60#if (LCD_HEIGHT < SYSVID_HEIGHT)
61enum { ROW_RESIZE_STEP = (LCD_HEIGHT << 16) / SYSVID_HEIGHT };
62
63static bool rowsToSkip[SYSVID_HEIGHT];
64
65/*
66 *
67 */
68static void calculateRowsToSkip(void)
69{
70 U32 currentRow, prevResizedRow;
71
72 prevResizedRow = 0;
73 rowsToSkip[0] = false;
74
75 for (currentRow = 1; currentRow < SYSVID_HEIGHT; ++currentRow)
76 {
77 U32 resizedRow = (currentRow * ROW_RESIZE_STEP) >> 16;
78 if (resizedRow == prevResizedRow)
79 {
80 rowsToSkip[currentRow] = true;
81 }
82 prevResizedRow = resizedRow;
83 }
84}
85#endif /* (LCD_HEIGHT < SYSVID_HEIGHT) */
86
87#if (LCD_WIDTH < SYSVID_WIDTH)
88enum { COLUMN_RESIZE_STEP = (LCD_WIDTH << 16) / (SYSVID_WIDTH + (DRAW_XYMAP_SCRLEFT*2)) };
89
90static bool columnsToSkip[SYSVID_WIDTH + (DRAW_XYMAP_SCRLEFT*2)];
91
92/*
93 *
94 */
95static void calculateColumnsToSkip(void)
96{
97 U32 currentColumn, prevResizedColumn;
98
99 prevResizedColumn = 0;
100 columnsToSkip[0] = false;
101
102 for (currentColumn = 1; currentColumn < (SYSVID_WIDTH + (DRAW_XYMAP_SCRLEFT*2)); ++currentColumn)
103 {
104 U32 resizedColumn = (currentColumn * COLUMN_RESIZE_STEP) >> 16;
105 if (resizedColumn == prevResizedColumn)
106 {
107 columnsToSkip[currentColumn] = true;
108 }
109 prevResizedColumn = resizedColumn;
110 }
111}
112#endif /* (LCD_WIDTH < SYSVID_WIDTH) */
113
114/*
115 *
116 */
117void sysvid_setPalette(img_color_t *pal, U16 n)
118{
119 U16 i;
120
121 for (i = 0; i < n; i++)
122 {
123#ifdef HAVE_LCD_COLOR
124 palette[i] = LCD_RGBPACK(pal[i].r, pal[i].g, pal[i].b);
125#else
126 palette[i] = ((3 * pal[i].r) + (6 * pal[i].g) + pal[i].b) / 10;
127#endif
128 }
129}
130
131/*
132 *
133 */
134void sysvid_setGamePalette()
135{
136 sysvid_setPalette(game_colors, game_color_count);
137}
138
139/*
140 * Update screen
141 */
142void sysvid_update(const rect_t *rects)
143{
144 unsigned sourceRow, sourceLastRow;
145 unsigned sourceColumn, sourceLastColumn;
146 unsigned resizedRow, resizedColumn;
147 unsigned resizedWidth, resizedHeight;
148 unsigned x, y;
149 U8 *sourceBuf, *sourceTemp;
150 fb_data *destBuf, *destTemp;
151
152 if (!rects)
153 {
154 return;
155 }
156
157 while (rects)
158 {
159 sourceRow = rects->y;
160 sourceLastRow = sourceRow + rects->height;
161 sourceColumn = rects->x;
162 sourceLastColumn = sourceColumn + rects->width;
163
164#if (LCD_WIDTH < SYSVID_WIDTH)
165 /* skip black borders */
166 if (sourceColumn < -DRAW_XYMAP_SCRLEFT)
167 {
168 sourceColumn = -DRAW_XYMAP_SCRLEFT;
169 }
170 if (sourceLastColumn > (SYSVID_WIDTH + DRAW_XYMAP_SCRLEFT))
171 {
172 sourceLastColumn = SYSVID_WIDTH + DRAW_XYMAP_SCRLEFT;
173 }
174
175 /* skip unwanted columns */
176 while (columnsToSkip[sourceColumn + DRAW_XYMAP_SCRLEFT] /* && sourceColumn < (SYSVID_WIDTH + DRAW_XYMAP_SCRLEFT) */)
177 {
178 ++sourceColumn;
179 }
180
181 resizedColumn = ((sourceColumn + DRAW_XYMAP_SCRLEFT) * COLUMN_RESIZE_STEP) >> 16;
182 resizedWidth = 0;
183#else
184 resizedColumn = sourceColumn;
185 resizedWidth = rects->width;
186#endif /* (LCD_WIDTH < SYSVID_WIDTH) */
187
188#if (LCD_HEIGHT < SYSVID_HEIGHT)
189 /* skip unwanted rows */
190 while (rowsToSkip[sourceRow] /* && sourceRow < SYSVID_HEIGHT */)
191 {
192 ++sourceRow;
193 }
194
195 resizedRow = (sourceRow * ROW_RESIZE_STEP) >> 16;
196 resizedHeight = 0;
197#else
198 resizedRow = sourceRow;
199 resizedHeight = rects->height;
200#endif /* (LCD_HEIGHT < SYSVID_HEIGHT) */
201
202 sourceBuf = sysvid_fb;
203 sourceBuf += sourceColumn + sourceRow * SYSVID_WIDTH;
204
205#ifdef HAVE_LCD_COLOR
206 if(!lcd_fb)
207 {
208 struct viewport *vp_main = rb->lcd_set_viewport(NULL);
209 lcd_fb = vp_main->buffer->fb_ptr;
210 }
211 destBuf = lcd_fb;
212#else
213 destBuf = greybuffer;
214#endif /* HAVE_LCD_COLOR */
215 destBuf += resizedColumn + resizedRow * LCD_WIDTH;
216
217#if (LCD_WIDTH < SYSVID_WIDTH)
218 sourceColumn += DRAW_XYMAP_SCRLEFT;
219 sourceLastColumn += DRAW_XYMAP_SCRLEFT;
220#endif /* (LCD_WIDTH < SYSVID_WIDTH) */
221
222 for (y = sourceRow; y < sourceLastRow; ++y)
223 {
224#if (LCD_HEIGHT < SYSVID_HEIGHT)
225 if (rowsToSkip[y])
226 {
227 sourceBuf += SYSVID_WIDTH;
228 continue;
229 }
230
231 ++resizedHeight;
232#endif /* (LCD_HEIGHT < SYSVID_HEIGHT) */
233
234 sourceTemp = sourceBuf;
235 destTemp = destBuf;
236 for (x = sourceColumn; x < sourceLastColumn; ++x)
237 {
238#if (LCD_WIDTH < SYSVID_WIDTH)
239 if (columnsToSkip[x])
240 {
241 ++sourceTemp;
242 continue;
243 }
244
245 if (y == sourceRow)
246 {
247 ++resizedWidth;
248 }
249#endif /* (LCD_WIDTH < SYSVID_WIDTH) */
250
251 *destTemp = palette[*sourceTemp];
252
253 ++sourceTemp;
254 ++destTemp;
255 }
256
257 sourceBuf += SYSVID_WIDTH;
258 destBuf += LCD_WIDTH;
259 }
260
261#ifdef HAVE_LCD_COLOR
262 IFDEBUG_VIDEO2(
263 for (y = resizedRow; y < resizedRow + resizedHeight; ++y)
264 {
265 destBuf = lcd_fb + resizedColumn + y * LCD_WIDTH;
266 *destBuf = palette[0x01];
267 *(destBuf + resizedWidth - 1) = palette[0x01];
268 }
269
270 for (x = resizedColumn; x < resizedColumn + resizedWidth; ++x)
271 {
272 destBuf = rb->lcd_fb + x + resizedRow * LCD_WIDTH;
273 *destBuf = palette[0x01];
274 *(destBuf + (resizedHeight - 1) * LCD_WIDTH) = palette[0x01];
275 }
276 );
277
278 rb->lcd_update_rect(resizedColumn, resizedRow, resizedWidth, resizedHeight);
279#else
280 grey_ub_gray_bitmap_part(greybuffer, resizedColumn, resizedRow, LCD_WIDTH, resizedColumn, resizedRow, resizedWidth, resizedHeight);
281#endif /* HAVE_LCD_COLOR */
282
283 rects = rects->next;
284 }
285}
286
287/*
288 * Clear screen
289 * (077C)
290 */
291void sysvid_clear(void)
292{
293 rb->memset(sysvid_fb, 0, sizeof(U8) * SYSVID_WIDTH * SYSVID_HEIGHT);
294}
295
296/*
297 * Initialise video
298 */
299bool sysvid_init()
300{
301 bool success;
302
303 if (isVideoInitialised)
304 {
305 return true;
306 }
307
308 IFDEBUG_VIDEO(sys_printf("xrick/video: start\n"););
309
310 success = false;
311 do
312 {
313 /* allocate xRick generic frame buffer into memory */
314 sysvid_fb = sysmem_push(sizeof(U8) * SYSVID_WIDTH * SYSVID_HEIGHT);
315 if (!sysvid_fb)
316 {
317 sys_error("(video) unable to allocate frame buffer");
318 break;
319 }
320
321#ifndef HAVE_LCD_COLOR
322 gbuf = sysmem_push(GREYBUFSIZE);
323 if (!gbuf)
324 {
325 sys_error("(video) unable to allocate buffer for greyscale functions");
326 break;
327 }
328
329 if (!grey_init(gbuf, GREYBUFSIZE, GREY_ON_COP, LCD_WIDTH, LCD_HEIGHT, NULL))
330 {
331 sys_error("(video) not enough memory to initialise greyscale functions");
332 break;
333 }
334#endif /* ndef HAVE_LCD_COLOR */
335
336 success = true;
337 } while (false);
338
339 if (!success)
340 {
341#ifndef HAVE_LCD_COLOR
342 sysmem_pop(gbuf);
343#endif
344 sysmem_pop(sysvid_fb);
345 return false;
346 }
347
348#if (LCD_HEIGHT < SYSVID_HEIGHT)
349 calculateRowsToSkip();
350#endif
351#if (LCD_WIDTH < SYSVID_WIDTH)
352 calculateColumnsToSkip();
353#endif
354
355#if LCD_DEPTH > 1
356 rb->lcd_set_backdrop(NULL);
357#endif
358 /* Turn off backlight timeout */
359 backlight_ignore_timeout();
360
361 rb->lcd_set_foreground(LCD_WHITE);
362 rb->lcd_set_background(LCD_BLACK);
363 rb->lcd_clear_display();
364
365#ifdef HAVE_LCD_COLOR
366 rb->lcd_update();
367#else
368 /* switch on greyscale overlay */
369 grey_show(true);
370#endif /* HAVE_LCD_COLOR */
371
372 isVideoInitialised = true;
373 IFDEBUG_VIDEO(sys_printf("xrick/video: ready\n"););
374 return true;
375}
376
377/*
378 * Shutdown video
379 */
380void sysvid_shutdown(void)
381{
382 if (!isVideoInitialised)
383 {
384 return;
385 }
386
387#ifndef HAVE_LCD_COLOR
388 grey_show(false);
389 grey_release();
390
391 sysmem_pop(gbuf);
392#endif /* ndef HAVE_LCD_COLOR */
393 sysmem_pop(sysvid_fb);
394
395 /* Turn on backlight timeout (revert to settings) */
396 backlight_use_settings();
397
398 isVideoInitialised = false;
399 IFDEBUG_VIDEO(sys_printf("xrick/video: stop\n"););
400}
401
402/* eof */
diff --git a/apps/plugins/xrick/util.c b/apps/plugins/xrick/util.c
new file mode 100644
index 0000000000..8926a00e5d
--- /dev/null
+++ b/apps/plugins/xrick/util.c
@@ -0,0 +1,230 @@
1/*
2 * xrick/util.c
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#include "xrick/util.h"
17
18#include "xrick/config.h"
19#include "xrick/game.h"
20#include "xrick/ents.h"
21#include "xrick/e_rick.h"
22#include "xrick/maps.h"
23#include "xrick/system/system.h"
24
25#include <string.h> /* memcpy */
26
27/*
28 * Full box test.
29 *
30 * ASM 1199
31 *
32 * e: entity to test against.
33 * x,y: coordinates to test.
34 * ret: true/(x,y) is within e's space, false/not.
35 */
36bool
37u_fboxtest(U8 e, S16 x, S16 y)
38{
39 if (ent_ents[e].x >= x ||
40 ent_ents[e].x + ent_ents[e].w < x ||
41 ent_ents[e].y >= y ||
42 ent_ents[e].y + ent_ents[e].h < y)
43 return false;
44 else
45 return true;
46}
47
48
49
50
51/*
52 * Box test (then whole e2 is checked agains the center of e1).
53 *
54 * ASM 113E
55 *
56 * e1: entity to test against (corresponds to DI in asm code).
57 * e2: entity to test (corresponds to SI in asm code).
58 * ret: true/intersect, false/not.
59 */
60bool
61u_boxtest(U8 e1, U8 e2)
62{
63 /* rick is special (may be crawling) */
64 if (e1 == E_RICK_NO)
65 return e_rick_boxtest(e2);
66
67 /*
68 * entity 1: x+0x05 to x+0x011, y to y+0x14
69 * entity 2: x to x+ .w, y to y+ .h
70 */
71 if (ent_ents[e1].x + 0x11 < ent_ents[e2].x ||
72 ent_ents[e1].x + 0x05 > ent_ents[e2].x + ent_ents[e2].w ||
73 ent_ents[e1].y + 0x14 < ent_ents[e2].y ||
74 ent_ents[e1].y > ent_ents[e2].y + ent_ents[e2].h - 1)
75 return false;
76 else
77 return true;
78}
79
80
81/*
82 * Compute the environment flag.
83 *
84 * ASM 0FBC if !crawl, else 103E
85 *
86 * x, y: coordinates where to compute the environment flag
87 * crawl: is rick crawling?
88 * rc0: anything CHANGED to the environment flag for crawling (6DBA)
89 * rc1: anything CHANGED to the environment flag (6DAD)
90 */
91void
92u_envtest(S16 x, S16 y, bool crawl, U8 *rc0, U8 *rc1)
93{
94 U8 i, xx;
95
96 /* prepare for ent #0 test */
97 ent_ents[ENT_ENTSNUM].x = x;
98 ent_ents[ENT_ENTSNUM].y = y;
99
100 i = 1;
101 if (!crawl) i++;
102 if (y & 0x0004) i++;
103
104 x += 4;
105 xx = (U8)x; /* FIXME? */
106
107 x = x >> 3; /* from pixels to tiles */
108 y = y >> 3; /* from pixels to tiles */
109
110 *rc0 = *rc1 = 0;
111
112 if (xx & 0x07) { /* tiles columns alignment */
113 if (crawl) {
114 *rc0 |= (map_eflg[map_map[y][x]] &
115 (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP));
116 *rc0 |= (map_eflg[map_map[y][x + 1]] &
117 (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP));
118 *rc0 |= (map_eflg[map_map[y][x + 2]] &
119 (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP));
120 y++;
121 }
122 do {
123 *rc1 |= (map_eflg[map_map[y][x]] &
124 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_FGND|
125 MAP_EFLG_LETHAL|MAP_EFLG_01));
126 *rc1 |= (map_eflg[map_map[y][x + 1]] &
127 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_FGND|
128 MAP_EFLG_LETHAL|MAP_EFLG_CLIMB|MAP_EFLG_01));
129 *rc1 |= (map_eflg[map_map[y][x + 2]] &
130 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_FGND|
131 MAP_EFLG_LETHAL|MAP_EFLG_01));
132 y++;
133 } while (--i > 0);
134
135 *rc1 |= (map_eflg[map_map[y][x]] &
136 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP|MAP_EFLG_FGND|
137 MAP_EFLG_LETHAL|MAP_EFLG_01));
138 *rc1 |= (map_eflg[map_map[y][x + 1]]);
139 *rc1 |= (map_eflg[map_map[y][x + 2]] &
140 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP|MAP_EFLG_FGND|
141 MAP_EFLG_LETHAL|MAP_EFLG_01));
142 }
143 else {
144 if (crawl) {
145 *rc0 |= (map_eflg[map_map[y][x]] &
146 (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP));
147 *rc0 |= (map_eflg[map_map[y][x + 1]] &
148 (MAP_EFLG_VERT|MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_WAYUP));
149 y++;
150 }
151 do {
152 *rc1 |= (map_eflg[map_map[y][x]] &
153 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_FGND|
154 MAP_EFLG_LETHAL|MAP_EFLG_CLIMB|MAP_EFLG_01));
155 *rc1 |= (map_eflg[map_map[y][x + 1]] &
156 (MAP_EFLG_SOLID|MAP_EFLG_SPAD|MAP_EFLG_FGND|
157 MAP_EFLG_LETHAL|MAP_EFLG_CLIMB|MAP_EFLG_01));
158 y++;
159 } while (--i > 0);
160
161 *rc1 |= (map_eflg[map_map[y][x]]);
162 *rc1 |= (map_eflg[map_map[y][x + 1]]);
163 }
164
165 /*
166 * If not lethal yet, and there's an entity on slot zero, and (x,y)
167 * boxtests this entity, then raise SOLID flag. This is how we make
168 * sure that no entity can move over the entity that is on slot zero.
169 *
170 * Beware! When game_cheat2 is set, this means that a block can
171 * move over rick without killing him -- but then rick is trapped
172 * because the block is solid.
173 */
174 if (!(*rc1 & MAP_EFLG_LETHAL)
175 && ent_ents[0].n
176 && u_boxtest(ENT_ENTSNUM, 0)) {
177 *rc1 |= MAP_EFLG_SOLID;
178 }
179
180 /* When game_cheat2 is set, the environment can not be lethal. */
181#ifdef ENABLE_CHEATS
182 if (game_cheat2) *rc1 &= ~MAP_EFLG_LETHAL;
183#endif
184}
185
186
187/*
188 * Check if x,y is within e trigger box.
189 *
190 * ASM 126F
191 * return: false if not in box, true if in box.
192 */
193bool
194u_trigbox(U8 e, S16 x, S16 y)
195{
196 U16 xmax, ymax;
197
198 xmax = ent_ents[e].trig_x + (ent_entdata[ent_ents[e].n & 0x7F].trig_w << 3);
199 ymax = ent_ents[e].trig_y + (ent_entdata[ent_ents[e].n & 0x7F].trig_h << 3);
200
201 if (xmax > 0xFF) xmax = 0xFF;
202
203 if (x <= ent_ents[e].trig_x || x > xmax ||
204 y <= ent_ents[e].trig_y || y > ymax)
205 return false;
206 else
207 return true;
208}
209
210/*
211 * Custom implementation of strdup function
212 */
213char *
214u_strdup(const char *sourceStr)
215{
216 char *destStr;
217 size_t length;
218
219 length = sys_strlen(sourceStr) + 1;
220 destStr = sysmem_push(length);
221 if (!destStr)
222 {
223 return NULL;
224 }
225 memcpy(destStr, sourceStr, length);
226 return destStr;
227}
228
229
230/* eof */
diff --git a/apps/plugins/xrick/util.h b/apps/plugins/xrick/util.h
new file mode 100644
index 0000000000..6a455ba0f6
--- /dev/null
+++ b/apps/plugins/xrick/util.h
@@ -0,0 +1,29 @@
1/*
2 * xrick/util.h
3 *
4 * Copyright (C) 1998-2002 BigOrno (bigorno@bigorno.net).
5 * Copyright (C) 2008-2014 Pierluigi Vicinanza.
6 * All rights reserved.
7 *
8 * The use and distribution terms for this software are contained in the file
9 * named README, which can be found in the root of this distribution. By
10 * using this software in any fashion, you are agreeing to be bound by the
11 * terms of this license.
12 *
13 * You must not remove this notice, or any other, from this software.
14 */
15
16#ifndef _UTIL_H
17#define _UTIL_H
18
19#include "xrick/system/basic_types.h"
20
21extern void u_envtest(S16, S16, bool, U8 *, U8 *);
22extern bool u_boxtest(U8, U8);
23extern bool u_fboxtest(U8, S16, S16);
24extern bool u_trigbox(U8, S16, S16);
25extern char * u_strdup(const char *);
26
27#endif /* ndef _UTIL_H */
28
29/* eof */
diff --git a/apps/plugins/xrick/xrick.make b/apps/plugins/xrick/xrick.make
new file mode 100644
index 0000000000..26406a957d
--- /dev/null
+++ b/apps/plugins/xrick/xrick.make
@@ -0,0 +1,31 @@
1# __________ __ ___.
2# Open \______ \ ____ ____ | | _\_ |__ _______ ___
3# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
4# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
5# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
6# \/ \/ \/ \/ \/
7# $Id$
8#
9
10XRICKSRCDIR := $(APPSDIR)/plugins/xrick
11XRICKBUILDDIR := $(BUILDDIR)/apps/plugins/xrick
12
13INCLUDES += -I$(XRICKSRCDIR)../ \
14 -I$(XRICKSRCDIR)/3rd_party
15
16ROCKS += $(XRICKBUILDDIR)/xrick.rock
17
18XRICK_SRC := $(call preprocess, $(XRICKSRCDIR)/SOURCES)
19XRICK_OBJ := $(call c2obj, $(XRICK_SRC))
20
21# add source files to OTHER_SRC to get automatic dependencies
22OTHER_SRC += $(XRICK_SRC)
23
24XRICKCFLAGS = $(PLUGINFLAGS) -std=gnu99 -O2
25
26$(XRICKBUILDDIR)/xrick.rock: $(XRICK_OBJ)
27
28# new rule needed to use extra compile flags
29$(XRICKBUILDDIR)/%.o: $(XRICKSRCDIR)/%.c
30 $(SILENT)mkdir -p $(dir $@)
31 $(call PRINTS,CC $(subst $(ROOTDIR)/,,$<))$(CC) $(XRICKCFLAGS) -c $< -o $@
diff --git a/docs/CREDITS b/docs/CREDITS
index fba9aed0d3..2fd7b35537 100644
--- a/docs/CREDITS
+++ b/docs/CREDITS
@@ -8,7 +8,7 @@
8 8
9People that have contributed to the project, one way or another. Friends! 9People that have contributed to the project, one way or another. Friends!
10 10
11Björn Stenberg 11Bjrn Stenberg
12Linus Nielsen Feltzing 12Linus Nielsen Feltzing
13Andy Choi 13Andy Choi
14Andrew Jamieson 14Andrew Jamieson
@@ -20,17 +20,17 @@ Gary Czvitkovicz
20Stuart Martin 20Stuart Martin
21Felix Arends 21Felix Arends
22Ulf Ralberg 22Ulf Ralberg
23David Härdeman 23David Hrdeman
24Thomas Saeys 24Thomas Saeys
25Grant Wier 25Grant Wier
26Julien Labruyére 26Julien Labruyre
27Nicolas Sauzede 27Nicolas Sauzede
28Robert Hak 28Robert Hak
29Dave Chapman 29Dave Chapman
30Stefan Meyer 30Stefan Meyer
31Eric Linenberg 31Eric Linenberg
32Tom Cvitan 32Tom Cvitan
33Magnus Öman 33Magnus man
34Jerome Kuptz 34Jerome Kuptz
35Julien Boissinot 35Julien Boissinot
36Nuutti Kotivuori 36Nuutti Kotivuori
@@ -59,14 +59,14 @@ Kjell Ericson
59Jim Hagani 59Jim Hagani
60Ludovic Lange 60Ludovic Lange
61Mike Holden 61Mike Holden
62Simon Elén 62Simon Eln
63Matthew P. O'Reilly 63Matthew P. O'Reilly
64Christian Schönberger 64Christian Schnberger
65Henrik Backe 65Henrik Backe
66Craig Sather 66Craig Sather
67José Maria Garcia-Valdecasas Bernal 67Jos Maria Garcia-Valdecasas Bernal
68Stevie Oh 68Stevie Oh
69Jörg Hohensohn 69Jrg Hohensohn
70Dave Jones 70Dave Jones
71Thomas Paul Diffenbach 71Thomas Paul Diffenbach
72Roland Kletzing 72Roland Kletzing
@@ -96,7 +96,7 @@ Jiri Jurecek
96Jacob Erlbeck 96Jacob Erlbeck
97Jean-Philippe Bernardy 97Jean-Philippe Bernardy
98Dave Hooper 98Dave Hooper
99Jonas Häggqvist 99Jonas Hggqvist
100Thom Johansen 100Thom Johansen
101Rinat Zakirov 101Rinat Zakirov
102Manuel Dejonghe 102Manuel Dejonghe
@@ -105,12 +105,12 @@ Michiel van der Kolk
105Tony Motakis 105Tony Motakis
106Andy Young 106Andy Young
107Alexandre Bourget 107Alexandre Bourget
108Richard S. La Charité III 108Richard S. La Charit III
109Christian Gmeiner 109Christian Gmeiner
110Tomas Salfischberger 110Tomas Salfischberger
111Miika Pekkarinen 111Miika Pekkarinen
112Tapio Karppinen 112Tapio Karppinen
113Richard Ottó O'Brien 113Richard Ott O'Brien
114Luca Burelli 114Luca Burelli
115Alessio Lenzi 115Alessio Lenzi
116David Bryant 116David Bryant
@@ -126,9 +126,9 @@ Hristo Kovachev
126Sander Sweers 126Sander Sweers
127Antonius Hellman 127Antonius Hellman
128Ryan Jackson 128Ryan Jackson
129Per Holmäng 129Per Holmng
130Frederic Devernay 130Frederic Devernay
131José M. Fandiño 131Jos M. Fandio
132Gadi Cohen 132Gadi Cohen
133Naftali Goldstein 133Naftali Goldstein
134David Dent 134David Dent
@@ -171,19 +171,19 @@ Mikael Magnusson
171Dominik Wenger 171Dominik Wenger
172Henrico Witvliet 172Henrico Witvliet
173Andrew Scott 173Andrew Scott
174Miguel A. Arévalo 174Miguel A. Arvalo
175Aaron F. Gonzalez 175Aaron F. Gonzalez
176Aleksey Kozyulin 176Aleksey Kozyulin
177Jani Kinnunen 177Jani Kinnunen
178Rui Marinho 178Rui Marinho
179Alun Thomas 179Alun Thomas
180Nils Wallménius 180Nils Wallmnius
181Naoaki Okazaki 181Naoaki Okazaki
182Will Dyson 182Will Dyson
183Matthias Mohr 183Matthias Mohr
184Christian Marg 184Christian Marg
185Eli Sherer 185Eli Sherer
186Fredrik Öhrn 186Fredrik hrn
187Nicolas Pennequin 187Nicolas Pennequin
188Ralf Herz 188Ralf Herz
189Michael DiFebbo 189Michael DiFebbo
@@ -204,18 +204,18 @@ Frederik Vestre
204Wenbin Leo 204Wenbin Leo
205Tom Evans 205Tom Evans
206Ewan Davies 206Ewan Davies
207Frédéric François 207Frdric Franois
208Marc-André Moreau 208Marc-Andr Moreau
209Ioannis Koutoulakis 209Ioannis Koutoulakis
210Alistair Marshall 210Alistair Marshall
211Karl Ove Hufthammer 211Karl Ove Hufthammer
212Víctor Zabalza 212Vctor Zabalza
213Ulrich Pegelow 213Ulrich Pegelow
214Andreas Mattsson 214Andreas Mattsson
215Daniel Ankers 215Daniel Ankers
216Paul Louden 216Paul Louden
217Rainer Sinsch 217Rainer Sinsch
218Plácido Revilla 218Plcido Revilla
219Michael Sevakis 219Michael Sevakis
220Lukas Sabota 220Lukas Sabota
221Emanuel Zephir 221Emanuel Zephir
@@ -243,13 +243,13 @@ Robert Kukla
243David Quesada 243David Quesada
244Jared Stafford 244Jared Stafford
245Martin Hensel 245Martin Hensel
246Stéphane Doyon 246Stphane Doyon
247Austin Appel 247Austin Appel
248Andre Smith 248Andre Smith
249Travis Hyyppa 249Travis Hyyppa
250Ian Webber 250Ian Webber
251Pavel Gnelitsa 251Pavel Gnelitsa
252Lutz Böhne 252Lutz Bhne
253Will Robertson 253Will Robertson
254Robert Carboneau 254Robert Carboneau
255Ye Wei 255Ye Wei
@@ -259,13 +259,13 @@ Chris Taylor
259Tobias Langhoff 259Tobias Langhoff
260Steve Gotthardt 260Steve Gotthardt
261Greg White 261Greg White
262Mattieu Favréaux 262Mattieu Favraux
263Malcolm Tyrrell 263Malcolm Tyrrell
264Piotr Jafiszow 264Piotr Jafiszow
265Gary Allen 265Gary Allen
266John BouAntoun 266John BouAntoun
267Tomasz Mon 267Tomasz Mon
268Jakub Matoušek 268Jakub Matou?ek
269Albert Veli 269Albert Veli
270Chris Dohan 270Chris Dohan
271Takashi Obara 271Takashi Obara
@@ -276,7 +276,7 @@ Sean Morrisey
276Shay Green 276Shay Green
277Nick Vanderweit 277Nick Vanderweit
278Simon Menzel 278Simon Menzel
279Timo Horstschäfer 279Timo Horstschfer
280Jacco Koning 280Jacco Koning
281Chris Ham 281Chris Ham
282Jose Ramon Garcia 282Jose Ramon Garcia
@@ -335,7 +335,7 @@ Alexander Eickhoff
335Ken Fazzone 335Ken Fazzone
336David Bishop 336David Bishop
337Hein-Pieter van Braam 337Hein-Pieter van Braam
338Przemysław Hołubowski 338Przemys?aw Ho?ubowski
339Stepan Moskovchenko 339Stepan Moskovchenko
340John S. Gwynne 340John S. Gwynne
341Brian J. Morey 341Brian J. Morey
@@ -343,12 +343,12 @@ Stijn Hisken
343Bertrik Sikken 343Bertrik Sikken
344Karim Boucher 344Karim Boucher
345James Espinoza 345James Espinoza
346Franz Rühmland 346Franz Rhmland
347Jordan Anderson 347Jordan Anderson
348Maurus Cuelenaere 348Maurus Cuelenaere
349Chris Allegretta 349Chris Allegretta
350Alastair S 350Alastair S
351Martin Crkovský 351Martin Crkovsk
352Ariya Hidayat 352Ariya Hidayat
353Jonas Hurrelmann 353Jonas Hurrelmann
354Lee Kang Hyuk 354Lee Kang Hyuk
@@ -356,7 +356,7 @@ Clemens Werther
356Robert Menes 356Robert Menes
357Henri Valta 357Henri Valta
358Melba Sitjar 358Melba Sitjar
359Mehmet Ş. Çatalbaş 359Mehmet ?. atalba?
360Scott Tinman 360Scott Tinman
361Alexander Kuzmenkov 361Alexander Kuzmenkov
362Thomas Martitz 362Thomas Martitz
@@ -366,7 +366,7 @@ Apoorva Mahajan
366Vuong Minh Hiep 366Vuong Minh Hiep
367Mateusz Kubica 367Mateusz Kubica
368Frank Gevaerts 368Frank Gevaerts
369Chelo Sacristán 369Chelo Sacristn
370Sascha Wolf 370Sascha Wolf
371Nickolay Jordanov 371Nickolay Jordanov
372Johannes Voggenthaler 372Johannes Voggenthaler
@@ -380,7 +380,7 @@ Ivan Pesic
380Marcel Barbulescu 380Marcel Barbulescu
381Phil Light 381Phil Light
382Rob Purchase 382Rob Purchase
383Andreas Müller 383Andreas Mller
384Christopher Williams 384Christopher Williams
385Martin Ritter 385Martin Ritter
386Justin Hannigan 386Justin Hannigan
@@ -409,39 +409,39 @@ Shunsuke Shimizu
409Tadayuki Nishizono 409Tadayuki Nishizono
410Jun Gu 410Jun Gu
411Daniel Weck 411Daniel Weck
412Clément Pit-Claudel 412Clment Pit-Claudel
413Jelle Geerts 413Jelle Geerts
414Tadeusz Pyś 414Tadeusz Py?
415Rostislav Chekan 415Rostislav Chekan
416Florin Popescu 416Florin Popescu
417Volker Mische 417Volker Mische
418Vitja Makarov 418Vitja Makarov
419Francisco Vila 419Francisco Vila
420Christian Lees 420Christian Lees
421Rafaël Carré 421Rafal Carr
422Denes Balatoni 422Denes Balatoni
423Roy Wallace 423Roy Wallace
424Eric Lassauge 424Eric Lassauge
425François Dinel 425Franois Dinel
426Francesco Rigoni 426Francesco Rigoni
427Joël Puik 427Jol Puik
428Klaas Bosteels 428Klaas Bosteels
429Teruaki Kawashima 429Teruaki Kawashima
430Marcin Łukasik 430Marcin ?ukasik
431Le Jin 431Le Jin
432Alex Bennee 432Alex Bennee
433Stéphane Quertinmont 433Stphane Quertinmont
434Bartosz Fabianowski 434Bartosz Fabianowski
435Adam Hogan 435Adam Hogan
436Andrew Mahone 436Andrew Mahone
437Anton Veretenenko 437Anton Veretenenko
438Vicente Ibarra 438Vicente Ibarra
439Rui Araújo 439Rui Arajo
440Brian Cloutier 440Brian Cloutier
441Olivier Barbut 441Olivier Barbut
442Yoshihisa Uchida 442Yoshihisa Uchida
443Sanggon Lee 443Sanggon Lee
444Kaspar Rothenfußer 444Kaspar Rothenfuer
445Ryan Press 445Ryan Press
446Craig Elliott 446Craig Elliott
447Kenderes Tamas 447Kenderes Tamas
@@ -453,7 +453,7 @@ Gareth Schakel
453Brian Sutherland 453Brian Sutherland
454Sam Bouwer 454Sam Bouwer
455Johannes Linke 455Johannes Linke
456Michaël Burtin 456Michal Burtin
457Sasha Khamkov 457Sasha Khamkov
458Kai Posadowsky 458Kai Posadowsky
459Jack Halpin 459Jack Halpin
@@ -504,14 +504,14 @@ Yann Muller
504Sascha Wilde 504Sascha Wilde
505Fred Bauer 505Fred Bauer
506Simon Rothen 506Simon Rothen
507Pavel Rzehák 507Pavel Rzehk
508Diego Herranz 508Diego Herranz
509Viktor Varga 509Viktor Varga
510Juliusz Chroboczek 510Juliusz Chroboczek
511Christian Beier 511Christian Beier
512Giovanni Zilli 512Giovanni Zilli
513Shiloh Hawley 513Shiloh Hawley
514Peter Lecký 514Peter Leck
515Wilfred Hughes 515Wilfred Hughes
516Laurent Gautier 516Laurent Gautier
517Simon Zhukovsky 517Simon Zhukovsky
@@ -528,36 +528,36 @@ Mark Borgerding
528Tobias Diedrich 528Tobias Diedrich
529Andrew Engelbrecht 529Andrew Engelbrecht
530Kevin Schoedel 530Kevin Schoedel
531Jens Theeß 531Jens Thee
532Alexey Nemtsev 532Alexey Nemtsev
533Pascal Below 533Pascal Below
534Danny Attar 534Danny Attar
535Philipp Stephani 535Philipp Stephani
536Tore Johnny Bråtveit 536Tore Johnny Brtveit
537Marcin Bukat 537Marcin Bukat
538Andrew Rodland 538Andrew Rodland
539Luca Leonardo Scorcia 539Luca Leonardo Scorcia
540Gerhard Zintel 540Gerhard Zintel
541Adrián Cereto Massagué 541Adrin Cereto Massagu
542Chris Savery 542Chris Savery
543Raphaël Jakse 543Raphal Jakse
544Wincent Balin 544Wincent Balin
545Aaron Rothbaum 545Aaron Rothbaum
546Nejc Lotric 546Nejc Lotric
547Hinrik Örn Sigurðsson 547Hinrik rn Sigursson
548Stephen Carroll 548Stephen Carroll
549Joe Balough 549Joe Balough
550Jérôme Heil 550Jrme Heil
551Tim Graf 551Tim Graf
552Martin Sägmüller 552Martin Sgmller
553Joshua Hulst 553Joshua Hulst
554Pierre-Yves Roosens 554Pierre-Yves Roosens
555Hayden Pearce 555Hayden Pearce
556Rodrigo Barretto 556Rodrigo Barretto
557Daniel Rigby 557Daniel Rigby
558Alexey Polkhirev 558Alexey Polkhirev
559István Nagy 559Istvn Nagy
560Wojciech Leśniak 560Wojciech Le?niak
561Tuomas Airaksinen 561Tuomas Airaksinen
562Calvin Walden 562Calvin Walden
563Michael Gentry 563Michael Gentry
@@ -572,12 +572,12 @@ Craig Mann
572William Peters 572William Peters
573Li Jie 573Li Jie
574Cristina Talpiga 574Cristina Talpiga
575Ştefan Moisei 575?tefan Moisei
576Alexander Meshcheryakov 576Alexander Meshcheryakov
577Ryan Sawhill 577Ryan Sawhill
578Thomas Jarosch 578Thomas Jarosch
579Will Sowerbutts 579Will Sowerbutts
580Łukasz Stelmach 580?ukasz Stelmach
581Gabriel Maia 581Gabriel Maia
582Robert Horn 582Robert Horn
583Ante Maretic 583Ante Maretic
@@ -586,12 +586,12 @@ Uwe Wiebach
586Mikhail Titov 586Mikhail Titov
587Dave Slusher 587Dave Slusher
588Jean-Marie Moraux 588Jean-Marie Moraux
589Ismael Castiñeira Álvarez 589Ismael Castieira lvarez
590Mārtiņš Šimis 590M?rti?? ?imis
591Huan Zhang 591Huan Zhang
592Leif Andersen 592Leif Andersen
593Sergiu Rotaru 593Sergiu Rotaru
594Noé Lojkine 594No Lojkine
595Ophir Lojkine 595Ophir Lojkine
596Stephan Grossklass 596Stephan Grossklass
597John Morris 597John Morris
@@ -616,7 +616,7 @@ Artur Juraszek
616Wieland Hoffmann 616Wieland Hoffmann
617Nathan Korth 617Nathan Korth
618Igor Petelin 618Igor Petelin
619Cástor Muñoz 619Cstor Muoz
620Albert Barca 620Albert Barca
621Fukuda Takafumi 621Fukuda Takafumi
622Dimitar Dimitrov 622Dimitar Dimitrov
@@ -649,8 +649,8 @@ Semyon Zhukovsky
649Kostadin Kolev 649Kostadin Kolev
650Jordi Prenafeta 650Jordi Prenafeta
651Tiago Medeiros 651Tiago Medeiros
652Udo Schläpfer 652Udo Schlpfer
653Åka Sikrom 653ka Sikrom
654Thomas White 654Thomas White
655Karl Huber 655Karl Huber
656Adam Sampson 656Adam Sampson
@@ -685,15 +685,16 @@ Martin Buck
685Stefan Ott 685Stefan Ott
686David Chionne 686David Chionne
687Wilfried Winkler 687Wilfried Winkler
688Johannes König 688Johannes Knig
689Alexander Drammen 689Alexander Drammen
690Kei Miyamoto 690Kei Miyamoto
691James D. Smith 691James D. Smith
692Howard Richardson 692Howard Richardson
693Aurlien Coudurier
693Sylvain Saubier 694Sylvain Saubier
694Adrián Tinoco 695Adrián Tinoco
695Boris Kovačević 696Boris Kovačević
696Stéphane Moutard-Martin 697Stphane Moutard-Martin
697Rune Pade 698Rune Pade
698Michael Rey 699Michael Rey
699Yuxuan Shui 700Yuxuan Shui
@@ -720,6 +721,7 @@ JJ Style
720Jerry Chapman 721Jerry Chapman
721Leander Lismond 722Leander Lismond
722Eren Akpolat 723Eren Akpolat
724Pierluigi Vicinanza
723 725
724The libmad team 726The libmad team
725The wavpack team 727The wavpack team
@@ -761,3 +763,4 @@ The bsdiff team
761The libtomcrypt team 763The libtomcrypt team
762The microtar team (rxi and others) 764The microtar team (rxi and others)
763The UnifontEX and GNU Unifont teams 765The UnifontEX and GNU Unifont teams
766The XRick team
diff --git a/manual/plugins/images/ss-xrick-220x176x16.png b/manual/plugins/images/ss-xrick-220x176x16.png
new file mode 100755
index 0000000000..5fb3a74a2f
--- /dev/null
+++ b/manual/plugins/images/ss-xrick-220x176x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-xrick-240x320x16.png b/manual/plugins/images/ss-xrick-240x320x16.png
new file mode 100755
index 0000000000..2d86387b15
--- /dev/null
+++ b/manual/plugins/images/ss-xrick-240x320x16.png
Binary files differ
diff --git a/manual/plugins/images/ss-xrick-320x240x16.png b/manual/plugins/images/ss-xrick-320x240x16.png
new file mode 100755
index 0000000000..7739445c35
--- /dev/null
+++ b/manual/plugins/images/ss-xrick-320x240x16.png
Binary files differ
diff --git a/manual/plugins/main.tex b/manual/plugins/main.tex
index c04299ca49..b2274f18af 100644
--- a/manual/plugins/main.tex
+++ b/manual/plugins/main.tex
@@ -111,8 +111,13 @@ text files%
111 111
112\input{plugins/xobox.tex} 112\input{plugins/xobox.tex}
113 113
114\opt{lcd_non-mono}{\input{plugins/xrick.tex}}
115
114\opt{lcd_color}{\input{plugins/xworld.tex}} 116\opt{lcd_color}{\input{plugins/xworld.tex}}
115 117
118
119
120
116\section{Demos} 121\section{Demos}
117 122
118\input{plugins/bounce.tex} 123\input{plugins/bounce.tex}
diff --git a/manual/plugins/xrick.tex b/manual/plugins/xrick.tex
new file mode 100755
index 0000000000..3aac6e08c8
--- /dev/null
+++ b/manual/plugins/xrick.tex
@@ -0,0 +1,107 @@
1% $Id$ %
2\subsection{xrick}
3\screenshot{plugins/images/ss-xrick}{xrick}{img:xrick}
4xrick is a clone of the platform game
5\emph{'Rick Dangerous'}
6(\url{http://en.wikipedia.org/wiki/Rick_Dangerous}),
7originally written by 'BigOrno'
8(\url{http://www.bigorno.net/xrick/}),
9modified and ported to Rockbox by Pierluigi Vicinanza
10(\url{https://github.com/pierluigi-vicinanza/xrick}).
11
12Walk through the maps, avoid traps, kill the Bad Guys... and
13try to stay alive long enough to accomplish your mission!
14
15Rick can fire bullets, lay sticks of dynamite, walk, crawl,
16climb, and also poke walls or Bad Guys with his stick.
17Poking walls can trigger traps, open doors, etc. although
18sometimes a dynamite stick or a bullet is needed.
19Go figure.
20
21\subsubsection{Getting started}
22For the game to run you need \fname{.dat} game files located in
23\fname{/.rockbox/xrick} on your \dap.
24Create the directory and extract xrick \fname{data.zip} archive into it.
25The needed files can be found at
26\url{https://github.com/pierluigi-vicinanza/xrick/blob/master/game/data.zip}.
27
28\subsubsection{Controls}
29By holding down \emph{Fire} and pressing \emph{Left} or \emph{Right},
30you can poke a wall (or anything else) with your stick.
31By holding down \emph{Fire} and pressing \emph{Down}, you can lay a stick of dynamite.
32By holding down \emph{Fire} and pressing \emph{Up}, you can fire a bullet.
33
34Throughout the game, use these buttons to control Rick:
35
36\begin{btnmap}
37%
38 \opt{iriverh300}{\ButtonUp/\ButtonRec}
39 \opt{fuzeplus}{\ButtonUp}
40 \opt{ipodvideo}{\ButtonMenu}
41 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginUp}
42 \opt{HAVEREMOTEKEYMAP}{& }
43 & Jump or Climb Up\\
44%
45 \opt{fuzeplus}{\ButtonPlay & Jump Right or Climb Up and Right\\}
46%
47 \opt{fuzeplus}{\ButtonBack & Jump Left or Climb Up and Left\\}
48%
49 \opt{iriverh300}{\ButtonDown/\ButtonMode}
50 \opt{fuzeplus}{\ButtonDown}
51 \opt{ipodvideo}{\ButtonPlay}
52 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginDown}
53 \opt{HAVEREMOTEKEYMAP}{& }
54 & Crouch or Climb Down\\
55%
56 \opt{fuzeplus}{\ButtonBottomRight & Crouch and Move Right or Climb Down and Right\\}
57%
58 \opt{fuzeplus}{\ButtonBottomLeft & Crouch and Move Left or Climb Down and Left\\}
59%
60 \opt{iriverh300,fuzeplus,ipodvideo}{\ButtonLeft}
61 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginLeft}
62 \opt{HAVEREMOTEKEYMAP}{& }
63 & Move Left\\
64%
65 \opt{iriverh300,fuzeplus,ipodvideo}{\ButtonRight}
66 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginRight}
67 \opt{HAVEREMOTEKEYMAP}{& }
68 & Move Right\\
69%
70 \opt{iriverh300}{\ButtonOn}
71 \opt{fuzeplus}{\ButtonVolDown}
72 \opt{ipodvideo}{\ButtonSelect}
73 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginSelect}
74
75 \opt{HAVEREMOTEKEYMAP}{& }
76 & Fire\\
77%
78 \opt{iriverh300}{\ButtonSelect}
79 \opt{fuzeplus}{\ButtonVolUp}
80 \opt{ipodvideo}{\ButtonScrollBack}
81 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginCancel}
82 \opt{HAVEREMOTEKEYMAP}{& }
83 & Pause\\
84%
85 \opt{iriverh300}{\ButtonOff}
86 \opt{fuzeplus}{\ButtonPower}
87 \opt{ipodvideo}{\ButtonScrollFwd}
88 \nopt{iriverh300,fuzeplus,ipodvideo}{\PluginExit}
89 \opt{hold_button}{/\ButtonHold}
90 \opt{HAVEREMOTEKEYMAP}{& }
91 & Menu\\
92%
93\end{btnmap}
94
95\subsubsection{Menu}
96\begin{description}
97 \item[Resume Game. ] Resume the game
98 \item[Restart Game. ] Restart the game
99 \item[Cheat Settings. ] This menu has the following options:
100
101 \emph{Enable Unlimited Lives/Ammo Mode. } Toggle trainer mode (always six bullets, six sticks, six Rick).\\
102 \emph{Enable Never Die Mode. } Toggle 'never die' mode (nothing can kill Rick). Use with care.
103 Although it lets you walk through Bad Guys unharmed, it can produce strange results.\\
104 \emph{Enable Expose Mode. } Toggle 'expose' mode (see all entities).%\\
105
106 \item[Quit. ] Quit the game
107\end{description}
diff --git a/utils/rbutilqt/base/playerbuildinfo.cpp b/utils/rbutilqt/base/playerbuildinfo.cpp
index c76abc4ffe..7edb7f750c 100644
--- a/utils/rbutilqt/base/playerbuildinfo.cpp
+++ b/utils/rbutilqt/base/playerbuildinfo.cpp
@@ -49,6 +49,7 @@ const static struct {
49 { PlayerBuildInfo::PuzzFontsUrl, "other/puzzfonts_url" }, 49 { PlayerBuildInfo::PuzzFontsUrl, "other/puzzfonts_url" },
50 { PlayerBuildInfo::QuakeUrl, "other/quake_url" }, 50 { PlayerBuildInfo::QuakeUrl, "other/quake_url" },
51 { PlayerBuildInfo::Wolf3DUrl, "other/wolf3d_url" }, 51 { PlayerBuildInfo::Wolf3DUrl, "other/wolf3d_url" },
52 { PlayerBuildInfo::XRickUrl, "other/xrick_url" },
52 { PlayerBuildInfo::XWorldUrl, "other/xworld_url" }, 53 { PlayerBuildInfo::XWorldUrl, "other/xworld_url" },
53 { PlayerBuildInfo::MidiPatchsetUrl, "other/patcheset_url" }, 54 { PlayerBuildInfo::MidiPatchsetUrl, "other/patcheset_url" },
54}; 55};
diff --git a/utils/rbutilqt/base/playerbuildinfo.h b/utils/rbutilqt/base/playerbuildinfo.h
index 85fc2ac6dc..38f6662e09 100644
--- a/utils/rbutilqt/base/playerbuildinfo.h
+++ b/utils/rbutilqt/base/playerbuildinfo.h
@@ -53,6 +53,7 @@ public:
53 QuakeUrl, 53 QuakeUrl,
54 Wolf3DUrl, 54 Wolf3DUrl,
55 XWorldUrl, 55 XWorldUrl,
56 XRickUrl,
56 MidiPatchsetUrl, 57 MidiPatchsetUrl,
57 }; 58 };
58 enum DeviceInfo { 59 enum DeviceInfo {
diff --git a/utils/rbutilqt/gui/selectiveinstallwidget.cpp b/utils/rbutilqt/gui/selectiveinstallwidget.cpp
index 28dd50d482..639e03308a 100644
--- a/utils/rbutilqt/gui/selectiveinstallwidget.cpp
+++ b/utils/rbutilqt/gui/selectiveinstallwidget.cpp
@@ -610,6 +610,7 @@ static const struct {
610 { "Quake", "games/quake.rock", PlayerBuildInfo::QuakeUrl }, 610 { "Quake", "games/quake.rock", PlayerBuildInfo::QuakeUrl },
611 { "Puzzles fonts", "games/sgt-blackbox.rock", PlayerBuildInfo::PuzzFontsUrl }, 611 { "Puzzles fonts", "games/sgt-blackbox.rock", PlayerBuildInfo::PuzzFontsUrl },
612 { "Wolf3D", "games/wolf3d.rock", PlayerBuildInfo::Wolf3DUrl }, 612 { "Wolf3D", "games/wolf3d.rock", PlayerBuildInfo::Wolf3DUrl },
613 { "XRick", "games/xrick.rock", PlayerBuildInfo::XRickUrl },
613 { "XWorld", "games/xworld.rock", PlayerBuildInfo::XWorldUrl }, 614 { "XWorld", "games/xworld.rock", PlayerBuildInfo::XWorldUrl },
614 { "MIDI Patchset", "viewers/midi.rock", PlayerBuildInfo::MidiPatchsetUrl }, 615 { "MIDI Patchset", "viewers/midi.rock", PlayerBuildInfo::MidiPatchsetUrl },
615}; 616};
diff --git a/utils/rbutilqt/rbutil.ini b/utils/rbutilqt/rbutil.ini
index f75cfe015e..bc41ff48b0 100644
--- a/utils/rbutilqt/rbutil.ini
+++ b/utils/rbutilqt/rbutil.ini
@@ -14,6 +14,7 @@ quake_url=https://download.rockbox.org/useful/quake.zip
14puzzfonts_url=https://download.rockbox.org/useful/sgt-fonts.zip 14puzzfonts_url=https://download.rockbox.org/useful/sgt-fonts.zip
15wolf3d_url=https://download.rockbox.org/useful/wolf3d.zip 15wolf3d_url=https://download.rockbox.org/useful/wolf3d.zip
16xworld_url=https://download.rockbox.org/useful/xworld.zip 16xworld_url=https://download.rockbox.org/useful/xworld.zip
17xrick_url=https://download.rockbox.org/useful/xrick-data.zip
17rbutil_url=https://download.rockbox.org/rbutil/ 18rbutil_url=https://download.rockbox.org/rbutil/
18 19
19[bootloader] 20[bootloader]