From 5337c81d6f92a301a73eda059f31c5e0c1dbdd9b Mon Sep 17 00:00:00 2001 From: Oldes Date: Wed, 28 Dec 2022 20:55:24 +0100 Subject: [PATCH] FEAT: new `swap-endian` native function for swapping binary byte order --- src/core/f-series.c | 69 ++++++++++++++++++++++++++++++++++ src/tests/units/series-test.r3 | 19 ++++++++++ 2 files changed, 88 insertions(+) diff --git a/src/core/f-series.c b/src/core/f-series.c index e38bbe4374..55bb04c5d4 100644 --- a/src/core/f-series.c +++ b/src/core/f-series.c @@ -29,6 +29,7 @@ ***********************************************************************/ #include "sys-core.h" +#include "stdio.h" #define THE_SIGN(v) ((v < 0) ? -1 : (v > 0) ? 1 : 0) @@ -381,3 +382,71 @@ Do_Act(D_RET, VAL_TYPE(D_ARG(1)), A_POKE); return R_RET; } + +/*********************************************************************** +** +*/ REBNATIVE(swap_endian) +/* +// swap-endian: native [ +// {Swaps byte order (endianess)} +// value [binary!] "At position (modified)" +// /width bytes [integer!] "2, 4 or 8 (default is 2)" +// /part "Limits to a given length or position" +// range [number! series!] +] +***********************************************************************/ +{ + REBCNT i; + REBCNT width = 2; + REBVAL *val = D_ARG(1); + REBYTE *bin = VAL_BIN_DATA(D_ARG(1)); + if (D_REF(2)) width = VAL_INT32(D_ARG(3)); + + REBCNT len = D_REF(4) ? Partial(val, 0, D_ARG(5), 0) : VAL_LEN(val); + if (len <= 0) return R_ARG1; + + switch(width) { + case 2: { + uint16_t *bp = (uint16_t *)bin; + uint16_t num; + len >>= 1; + for (i = 0; i < len; i++) { + num = bp[i]; + bp[i] = (((num & 0x00FF) << 8) | + ((num & 0xFF00) >> 8)); + } + break; + } + case 4: { + uint32_t *bp = (uint32_t *)bin; + uint32_t num; + len >>= 2; + for (i = 0; i < len; i++) { + num = bp[i]; + bp[i] = (((num & 0x000000FF) << 24) | + ((num & 0x0000FF00) << 8) | + ((num & 0x00FF0000) >> 8) | + ((num & 0xFF000000) >> 24)); + } + break; + } + case 8: { + uint64_t *bp = (uint64_t *)bin; + uint64_t num; + len >>= 3; + for (i = 0; i < len; i++) { + num = bp[i]; + num = ((num << 8) & 0xFF00FF00FF00FF00ULL) | + ((num >> 8) & 0x00FF00FF00FF00FFULL); + num = ((num << 16) & 0xFFFF0000FFFF0000ULL) | + ((num >> 16) & 0x0000FFFF0000FFFFULL); + bp[i] = (num << 32) | (num >> 32); + } + break; + } + default: + Trap1(RE_INVALID_ARG, D_ARG(3)); + } + + return R_ARG1; +} diff --git a/src/tests/units/series-test.r3 b/src/tests/units/series-test.r3 index df4e4f52c2..a3c6fa20f3 100644 --- a/src/tests/units/series-test.r3 +++ b/src/tests/units/series-test.r3 @@ -2504,6 +2504,25 @@ Rebol [ ===end-group=== + +===start-group=== "SWAP-ENDIAN" +--test-- "swap-endian/width 2" + --assert #{FF00FF00FF00} = swap-endian #{00FF00FF00FF} + --assert #{FF00FF00AA} = swap-endian #{00FF00FFAA} ; the last not padded byte is ignored +--test-- "swap-endian/width 4" + --assert #{4433221188776655} = swap-endian/width #{1122334455667788} 4 + --assert #{44332211AAAA} = swap-endian/width #{11223344AAAA} 4 +--test-- "swap-endian/width 8" + --assert #{7766554433221100FFEEDDCCBBAA9988} = swap-endian/width #{00112233445566778899AABBCCDDEEFF} 8 + --assert #{7766554433221100AAAA} = swap-endian/width #{0011223344556677AAAA} 8 +--test-- "swap-endian/part" + --assert #{FF00FF001122} = swap-endian/part #{00FF00FF1122} 4 + --assert #{FF00FF001122} = swap-endian/part #{00FF00FF1122} 5 + --assert #{FF00FF002211} = swap-endian/part #{00FF00FF1122} 6 + --assert #{4433221155667788} = swap-endian/width/part #{1122334455667788} 4 4 + --assert #{77665544332211008899AABBCCDDEEFF} = swap-endian/width/part #{00112233445566778899AABBCCDDEEFF} 8 8 +===end-group=== + ;-- VECTOR related tests moved to %vector-test.r3 ~~~end-file~~~ \ No newline at end of file