Skip to content

Commit

Permalink
FEAT: new swap-endian native function for swapping binary byte order
Browse files Browse the repository at this point in the history
  • Loading branch information
Oldes committed Dec 28, 2022
1 parent de9a63c commit 5337c81
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
69 changes: 69 additions & 0 deletions src/core/f-series.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
***********************************************************************/

#include "sys-core.h"
#include "stdio.h"

#define THE_SIGN(v) ((v < 0) ? -1 : (v > 0) ? 1 : 0)

Expand Down Expand Up @@ -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;
}
19 changes: 19 additions & 0 deletions src/tests/units/series-test.r3
Original file line number Diff line number Diff line change
Expand Up @@ -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~~~

0 comments on commit 5337c81

Please sign in to comment.