Skip to content

Commit

Permalink
NDS, 3DS, DOS: use Z_BEST_SPEED as the zip compression level.
Browse files Browse the repository at this point in the history
  • Loading branch information
AliceLR committed Nov 14, 2023
1 parent c08a103 commit 5a04601
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 7 deletions.
3 changes: 3 additions & 0 deletions docs/changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ USERS
+ Robotic debugger watchpoints can now watch for particular
counter or string values. Leaving the value field blank will
still check for any value.
+ The NDS, 3DS, and DOS ports now write zip archives with the
fastest zlib compression level. This makes saved files that
use compression (worlds, saves, etc.) slightly larger.
+ editor_show_thing_toggles is now enabled by default.
- board_editor_hide_help and robot_editor_hide_help are no
longer enabled by default for accessibility.
Expand Down
31 changes: 26 additions & 5 deletions src/io/zip.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,19 @@
// The 3DS has incredibly slow file access that seems to be negatively impacted
// by backwards seeks in particular, so enable data descriptors for it too.
// The Switch may similarly benefit with this.
// DJGPP may be running on exceptionally slow hardware.

#if defined(CONFIG_NDS) || defined(CONFIG_3DS) || defined(CONFIG_SWITCH)
#if defined(CONFIG_NDS) || defined(CONFIG_3DS) || defined(CONFIG_SWITCH) || \
defined(CONFIG_DJGPP)
#define ZIP_WRITE_DATA_DESCRIPTOR
#endif

// Similarly, some platforms are slow and need faster compression.
// TODO: these should probably be runtime configurable instead.
#if defined(CONFIG_NDS) || defined(CONFIG_3DS) || defined(CONFIG_DJGPP)
#define ZIP_WRITE_DEFLATE_FAST
#endif

#define ZIP_VERSION_MINIMUM 20
#define ZIP64_VERSION_MINIMUM 45
#define ZIP_VERSION(x) ((x) & 0x00ff)
Expand Down Expand Up @@ -2086,10 +2094,13 @@ static enum zip_error zip_write_open_stream(struct zip_archive *zp,
return ZIP_ALLOC_ERROR;

// Set up the header
#ifdef ZIP_WRITE_DATA_DESCRIPTOR
fh->flags = ZIP_F_DATA_DESCRIPTOR;
#else
fh->flags = 0;
#ifdef ZIP_WRITE_DATA_DESCRIPTOR
fh->flags |= ZIP_F_DATA_DESCRIPTOR;
#endif
#ifdef ZIP_WRITE_DEFLATE_FAST
if(method == ZIP_M_DEFLATE)
fh->flags |= ZIP_F_DEFLATE_FAST;
#endif
fh->method = method;
fh->crc32 = 0;
Expand Down Expand Up @@ -2124,7 +2135,7 @@ static enum zip_error zip_write_open_stream(struct zip_archive *zp,
if(zp->stream)
{
struct zip_stream_data *stream_data = zp->stream_data;
zp->stream->compress_open(stream_data, method, false);
zp->stream->compress_open(stream_data, method, fh->flags);

result = zip_set_stream_buffer_size(zp, ZIP_STREAM_BUFFER_SIZE);
if(result != ZIP_SUCCESS)
Expand Down Expand Up @@ -2165,6 +2176,16 @@ static enum zip_error zip_write_autodetect_zip64(struct zip_archive *zp,
if(zp->stream != NULL && zp->stream->compress_bound != NULL)
{
size_t bound_len = 0;
int flags = 0;

// Bounding requires initializing the zstream, so initialize first
// using the correct compression level.
#ifdef ZIP_WRITE_DEFLATE_FAST
if(method == ZIP_M_DEFLATE)
flags |= ZIP_F_DEFLATE_FAST;
#endif

zp->stream->compress_open(zp->stream_data, method, flags);
result = zp->stream->compress_bound(zp->stream_data, src_len, &bound_len);
if(result)
return result;
Expand Down
4 changes: 4 additions & 0 deletions src/io/zip.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ enum zip_general_purpose_flag
#define ZIP_F_UNUSED (ZIP_F_UNUSED_7 | ZIP_F_UNUSED_8 | ZIP_F_UNUSED_9 |\
ZIP_F_UNUSED_10 | ZIP_F_UNUSED_12 | ZIP_F_UNUSED_14 | ZIP_F_UNUSED_15)

// DEFLATE-specific compression flags.
#define ZIP_F_DEFLATE_MAXIMUM ZIP_F_COMPRESSION_1
#define ZIP_F_DEFLATE_FAST ZIP_F_COMPRESSION_2

enum zip_internal_state
{
ZIP_S_READ_UNINITIALIZED,
Expand Down
19 changes: 17 additions & 2 deletions src/io/zip_deflate.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct deflate_stream_data
boolean is_inflate;
boolean is_deflate;
boolean should_finish;
uint16_t flags;
};

static inline struct zip_stream_data *deflate_create(void)
Expand Down Expand Up @@ -72,10 +73,18 @@ static inline void deflate_open(struct zip_stream_data *zs, uint16_t method,
uint16_t flags)
{
struct deflate_stream_data *ds = ((struct deflate_stream_data *)zs);
int prev_flags = ds->flags;
// Only clear the common portion of the stream data.
memset(zs, 0, sizeof(struct zip_stream_data));
zs->is_compression_stream = true;
ds->should_finish = false;
ds->flags = flags & (ZIP_F_DEFLATE_MAXIMUM | ZIP_F_DEFLATE_FAST);

if(ds->is_deflate && prev_flags != ds->flags)
{
deflateEnd(&(ds->z));
ds->is_deflate = false;
}
}

static inline void deflate_close(struct zip_stream_data *zs,
Expand Down Expand Up @@ -199,9 +208,15 @@ static inline enum zip_error deflate_init(struct zip_stream_data *zs)

if(!ds->is_deflate)
{
int level = Z_DEFAULT_COMPRESSION;
if(ds->flags & ZIP_F_DEFLATE_MAXIMUM)
level = Z_BEST_COMPRESSION;
if(ds->flags & ZIP_F_DEFLATE_FAST)
level = Z_BEST_SPEED;

// This is a raw deflate stream, so use -MAX_WBITS.
// Note: aside from the windowbits, these are all defaults.
deflateInit2(&(ds->z), Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
// Note: aside from the compression and windowbits, these are all defaults.
deflateInit2(&(ds->z), level, Z_DEFLATED, -MAX_WBITS,
8, Z_DEFAULT_STRATEGY);
ds->is_deflate = true;
}
Expand Down

0 comments on commit 5a04601

Please sign in to comment.