|
57 | 57 | #include "term.h"
|
58 | 58 | #include "unicode.h"
|
59 | 59 | #include "utils.h"
|
| 60 | +#ifdef WITH_ZLIB |
| 61 | +#include "zlib.h" |
| 62 | +#endif |
60 | 63 |
|
61 | 64 | #define MAX_NIF_NAME_LEN 260
|
62 | 65 | #define FLOAT_BUF_SIZE 64
|
@@ -186,6 +189,7 @@ static term nif_maps_next(Context *ctx, int argc, term argv[]);
|
186 | 189 | static term nif_unicode_characters_to_list(Context *ctx, int argc, term argv[]);
|
187 | 190 | static term nif_unicode_characters_to_binary(Context *ctx, int argc, term argv[]);
|
188 | 191 | static term nif_erlang_lists_subtract(Context *ctx, int argc, term argv[]);
|
| 192 | +static term nif_zlib_compress_1(Context *ctx, int argc, term argv[]); |
189 | 193 |
|
190 | 194 | #define DECLARE_MATH_NIF_FUN(moniker) \
|
191 | 195 | static term nif_math_##moniker(Context *ctx, int argc, term argv[]);
|
@@ -792,6 +796,12 @@ static const struct Nif erlang_lists_subtract_nif =
|
792 | 796 | .base.type = NIFFunctionType,
|
793 | 797 | .nif_ptr = nif_erlang_lists_subtract
|
794 | 798 | };
|
| 799 | +static const struct Nif zlib_compress_nif = |
| 800 | +{ |
| 801 | + .base.type = NIFFunctionType, |
| 802 | + .nif_ptr = nif_zlib_compress_1 |
| 803 | +}; |
| 804 | + |
795 | 805 |
|
796 | 806 | #define DEFINE_MATH_NIF(moniker) \
|
797 | 807 | static const struct Nif math_##moniker##_nif = \
|
@@ -2411,59 +2421,69 @@ static term nif_erlang_float_to_list(Context *ctx, int argc, term argv[])
|
2411 | 2421 | return make_list_from_ascii_buf((uint8_t *) float_buf, len, ctx);
|
2412 | 2422 | }
|
2413 | 2423 |
|
2414 |
| -static term nif_erlang_list_to_binary_1(Context *ctx, int argc, term argv[]) |
| 2424 | +static term list_to_binary(term list, term *ret, Context *ctx) |
2415 | 2425 | {
|
2416 |
| - UNUSED(argc); |
2417 |
| - |
2418 |
| - term t = argv[0]; |
2419 |
| - VALIDATE_VALUE(t, term_is_list); |
2420 |
| - |
2421 | 2426 | size_t bin_size;
|
2422 |
| - switch (interop_iolist_size(t, &bin_size)) { |
| 2427 | + switch (interop_iolist_size(list, &bin_size)) { |
2423 | 2428 | case InteropOk:
|
2424 | 2429 | break;
|
2425 | 2430 | case InteropMemoryAllocFail:
|
2426 |
| - RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 2431 | + return OUT_OF_MEMORY_ATOM; |
2427 | 2432 | case InteropBadArg:
|
2428 |
| - RAISE_ERROR(BADARG_ATOM); |
| 2433 | + return BADARG_ATOM; |
2429 | 2434 | }
|
2430 | 2435 |
|
2431 | 2436 | char *bin_buf = NULL;
|
2432 | 2437 | bool buf_allocated = true;
|
2433 | 2438 | if (bin_size > 0) {
|
2434 | 2439 | bin_buf = malloc(bin_size);
|
2435 | 2440 | if (IS_NULL_PTR(bin_buf)) {
|
2436 |
| - RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 2441 | + return OUT_OF_MEMORY_ATOM; |
2437 | 2442 | }
|
2438 | 2443 |
|
2439 |
| - switch (interop_write_iolist(t, bin_buf)) { |
| 2444 | + switch (interop_write_iolist(list, bin_buf)) { |
2440 | 2445 | case InteropOk:
|
2441 | 2446 | break;
|
2442 | 2447 | case InteropMemoryAllocFail:
|
2443 | 2448 | free(bin_buf);
|
2444 |
| - RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 2449 | + return OUT_OF_MEMORY_ATOM; |
2445 | 2450 | case InteropBadArg:
|
2446 | 2451 | free(bin_buf);
|
2447 |
| - RAISE_ERROR(BADARG_ATOM); |
| 2452 | + return BADARG_ATOM; |
2448 | 2453 | }
|
2449 | 2454 | } else {
|
2450 | 2455 | bin_buf = "";
|
2451 | 2456 | buf_allocated = false;
|
2452 | 2457 | }
|
2453 | 2458 |
|
2454 |
| - if (UNLIKELY(memory_ensure_free_with_roots(ctx, term_binary_heap_size(bin_size), 1, argv, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) { |
| 2459 | + if (UNLIKELY(memory_ensure_free(ctx, term_binary_heap_size(bin_size)) != MEMORY_GC_OK)) { |
2455 | 2460 | if (buf_allocated) {
|
2456 | 2461 | free(bin_buf);
|
2457 | 2462 | }
|
2458 |
| - RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 2463 | + return OUT_OF_MEMORY_ATOM; |
2459 | 2464 | }
|
2460 | 2465 | term bin_res = term_from_literal_binary(bin_buf, bin_size, &ctx->heap, ctx->global);
|
2461 | 2466 |
|
2462 | 2467 | if (buf_allocated) {
|
2463 | 2468 | free(bin_buf);
|
2464 | 2469 | }
|
| 2470 | + *ret = bin_res; |
2465 | 2471 |
|
2466 |
| - return bin_res; |
| 2472 | + return OK_ATOM; |
| 2473 | +} |
| 2474 | + |
| 2475 | +static term nif_erlang_list_to_binary_1(Context *ctx, int argc, term argv[]) |
| 2476 | +{ |
| 2477 | + UNUSED(argc); |
| 2478 | + |
| 2479 | + term t = argv[0]; |
| 2480 | + VALIDATE_VALUE(t, term_is_list); |
| 2481 | + term ret; |
| 2482 | + term result = list_to_binary(t, &ret, ctx); |
| 2483 | + if (UNLIKELY(result != OK_ATOM)) { |
| 2484 | + RAISE_ERROR(result); |
| 2485 | + } |
| 2486 | + return ret; |
2467 | 2487 | }
|
2468 | 2488 |
|
2469 | 2489 | static avm_int_t to_digit_index(avm_int_t character)
|
@@ -5257,6 +5277,61 @@ static term nif_erlang_lists_subtract(Context *ctx, int argc, term argv[])
|
5257 | 5277 | free(cons);
|
5258 | 5278 | return result;
|
5259 | 5279 | }
|
| 5280 | + |
| 5281 | +#ifdef WITH_ZLIB |
| 5282 | +static term nif_zlib_compress_1(Context *ctx, int argc, term argv[]) |
| 5283 | +{ |
| 5284 | + UNUSED(argc) |
| 5285 | + term to_compress = argv[0]; |
| 5286 | + if (term_is_list(to_compress)) { |
| 5287 | + term to_compress_binary; |
| 5288 | + term result = list_to_binary(to_compress, &to_compress_binary, ctx); |
| 5289 | + if (result != OK_ATOM) { |
| 5290 | + RAISE_ERROR(result); |
| 5291 | + } |
| 5292 | + to_compress = to_compress_binary; |
| 5293 | + } |
| 5294 | + if (UNLIKELY(!term_is_binary(to_compress))) { |
| 5295 | + RAISE_ERROR(BADARG_ATOM); |
| 5296 | + } |
| 5297 | + |
| 5298 | + size_t size = term_binary_size(to_compress); |
| 5299 | + // to_allocate is an upper bound for compression size |
| 5300 | + // changes to actual size after calling compress |
| 5301 | + uLong to_allocate = compressBound(size); |
| 5302 | + // Bytef is an unsigned char, term_binary_data return const *char |
| 5303 | + const Bytef *to_compress_data = (const Bytef *) term_binary_data(to_compress); |
| 5304 | + Bytef *compressed = malloc(to_allocate); |
| 5305 | + if (IS_NULL_PTR(compressed)) { |
| 5306 | + RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 5307 | + } |
| 5308 | + |
| 5309 | + int z_ret = compress(compressed, &to_allocate, to_compress_data, size); |
| 5310 | + if (UNLIKELY(z_ret != Z_OK)) { |
| 5311 | + free(compressed); |
| 5312 | + RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 5313 | + } |
| 5314 | + |
| 5315 | + if (UNLIKELY(memory_ensure_free(ctx, term_binary_data_size_in_terms(to_allocate)) != MEMORY_GC_OK)) { |
| 5316 | + free(compressed); |
| 5317 | + RAISE_ERROR(OUT_OF_MEMORY_ATOM); |
| 5318 | + } |
| 5319 | + term bin_res = term_from_literal_binary(compressed, to_allocate, &ctx->heap, ctx->global); |
| 5320 | + free(compressed); |
| 5321 | + return bin_res; |
| 5322 | +} |
| 5323 | +#endif |
| 5324 | +#ifndef WITH_ZLIB |
| 5325 | +static term nif_zlib_compress_1(Context *ctx, int argc, term argv[]) |
| 5326 | +{ |
| 5327 | + UNUSED(argc) |
| 5328 | + UNUSED(argv) |
| 5329 | + UNUSED(ctx) |
| 5330 | + fprintf(stderr, "Error: zlib library needed to use zlib:compress/1\n"); |
| 5331 | + RAISE_ERROR(UNDEFINED_ATOM); |
| 5332 | +} |
| 5333 | +#endif |
| 5334 | + |
5260 | 5335 | //
|
5261 | 5336 | // MAINTENANCE NOTE: Exception handling for fp operations using math
|
5262 | 5337 | // error handling is designed to be thread-safe, as errors are specified
|
|
0 commit comments