Skip to content

Commit

Permalink
Add compression API
Browse files Browse the repository at this point in the history
  • Loading branch information
ShadowNinja committed Sep 20, 2014
1 parent d6e28c1 commit 406ed5e
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 7 deletions.
12 changes: 12 additions & 0 deletions doc/lua_api.txt
Expand Up @@ -1763,6 +1763,18 @@ minetest.deserialize(string) -> table
^ Example: deserialize('return { ["foo"] = "bar" }') -> {foo='bar'}
^ Example: deserialize('print("foo")') -> nil (function call fails)
^ error:[string "print("foo")"]:1: attempt to call global 'print' (a nil value)
minetest.compress(data, method, ...) -> compressed_data
^ Compress a string of data.
^ `method` is a string identifying the compression method to be used.
^ Supported compression methods:
^ Deflate (zlib): "deflate"
^ `...` indicates method-specific arguments. Currently defined arguments are:
^ Deflate: `level` - Compression level, 0-9 or nil.
minetest.decompress(compressed_data, method, ...) -> data
^ Decompress a string of data (using ZLib).
^ See documentation on minetest.compress() for supported compression methods.
^ currently supported.
^ `...` indicates method-specific arguments. Currently, no methods use this.
minetest.is_protected(pos, name) -> bool
^ This function should be overridden by protection mods and should be used to
check if a player can interact at a position.
Expand Down
41 changes: 41 additions & 0 deletions src/script/lua_api/l_util.cpp
Expand Up @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/c_converter.h"
#include "common/c_content.h"
#include "cpp_api/s_async.h"
#include "serialization.h"
#include "debug.h"
#include "porting.h"
#include "log.h"
Expand Down Expand Up @@ -283,6 +284,40 @@ int ModApiUtil::l_get_builtin_path(lua_State *L)
return 1;
}

// compress(data, method, level)
int ModApiUtil::l_compress(lua_State *L)
{
size_t size;
const char *data = luaL_checklstring(L, 1, &size);

int level = -1;
if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
level = luaL_checknumber(L, 3);

std::ostringstream os;
compressZlib(std::string(data, size), os, level);

std::string out = os.str();

lua_pushlstring(L, out.data(), out.size());
return 1;
}

// decompress(data, method)
int ModApiUtil::l_decompress(lua_State *L)
{
size_t size;
const char * data = luaL_checklstring(L, 1, &size);

std::istringstream is(std::string(data, size));
std::ostringstream os;
decompressZlib(is, os);

std::string out = os.str();

lua_pushlstring(L, out.data(), out.size());
return 1;
}

void ModApiUtil::Initialize(lua_State *L, int top)
{
Expand All @@ -306,6 +341,9 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(is_yes);

API_FCT(get_builtin_path);

API_FCT(compress);
API_FCT(decompress);
}

void ModApiUtil::InitializeAsync(AsyncEngine& engine)
Expand All @@ -325,5 +363,8 @@ void ModApiUtil::InitializeAsync(AsyncEngine& engine)
ASYNC_API_FCT(is_yes);

ASYNC_API_FCT(get_builtin_path);

ASYNC_API_FCT(compress);
ASYNC_API_FCT(decompress);
}

6 changes: 6 additions & 0 deletions src/script/lua_api/l_util.h
Expand Up @@ -81,6 +81,12 @@ class ModApiUtil : public ModApiBase {
// get_scriptdir()
static int l_get_builtin_path(lua_State *L);

// compress(data, method, ...)
static int l_compress(lua_State *L);

// decompress(data, method, ...)
static int l_decompress(lua_State *L);

public:
static void Initialize(lua_State *L, int top);

Expand Down
9 changes: 4 additions & 5 deletions src/serialization.cpp
Expand Up @@ -53,7 +53,7 @@ void zerr(int ret)
}
}

void compressZlib(SharedBuffer<u8> data, std::ostream &os)
void compressZlib(SharedBuffer<u8> data, std::ostream &os, int level)
{
z_stream z;
const s32 bufsize = 16384;
Expand All @@ -65,7 +65,7 @@ void compressZlib(SharedBuffer<u8> data, std::ostream &os)
z.zfree = Z_NULL;
z.opaque = Z_NULL;

ret = deflateInit(&z, -1);
ret = deflateInit(&z, level);
if(ret != Z_OK)
throw SerializationError("compressZlib: deflateInit failed");

Expand Down Expand Up @@ -94,13 +94,12 @@ void compressZlib(SharedBuffer<u8> data, std::ostream &os)
}

deflateEnd(&z);

}

void compressZlib(const std::string &data, std::ostream &os)
void compressZlib(const std::string &data, std::ostream &os, int level)
{
SharedBuffer<u8> databuf((u8*)data.c_str(), data.size());
compressZlib(databuf, os);
compressZlib(databuf, os, level);
}

void decompressZlib(std::istream &is, std::ostream &os)
Expand Down
4 changes: 2 additions & 2 deletions src/serialization.h
Expand Up @@ -78,8 +78,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
Misc. serialization functions
*/

void compressZlib(SharedBuffer<u8> data, std::ostream &os);
void compressZlib(const std::string &data, std::ostream &os);
void compressZlib(SharedBuffer<u8> data, std::ostream &os, int level = -1);
void compressZlib(const std::string &data, std::ostream &os, int level = -1);
void decompressZlib(std::istream &is, std::ostream &os);

// These choose between zlib and a self-made one according to version
Expand Down

4 comments on commit 406ed5e

@4aiman
Copy link
Contributor

@4aiman 4aiman commented on 406ed5e Oct 31, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this addition?
(No offence, I really can't get it.)

@ShadowNinja
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@4aiman: It's for mods that write a lot of data to the disk (or network with LuaSocket, if the endoint supports it).
For example this can be used to compress WorldEdit schematics.

@4aiman
Copy link
Contributor

@4aiman 4aiman commented on 406ed5e Nov 5, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I can write a mod to compress some schematics and use those compressed files within another mod?

@ShadowNinja
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@4aiman: Yes, although you should provide an API for loading the schematics and not expose the underlying format.

Please sign in to comment.