summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--buf.c81
-rw-r--r--buf.h1
-rw-r--r--lib.c2
-rw-r--r--lib.h1
-rw-r--r--tests/012/buf.tl11
-rw-r--r--txr.175
6 files changed, 170 insertions, 1 deletions
diff --git a/buf.c b/buf.c
index daf00202..ffa2af3b 100644
--- a/buf.c
+++ b/buf.c
@@ -1913,6 +1913,86 @@ val buf_binary_width(val buf)
}
}
+val buf_xor_pattern(val buf, val pat)
+{
+ val self = lit("buf-xor-pattern");
+ struct buf *b = buf_handle(buf, self);
+ ucnum l = c_unum(b->len, self), pl;
+ mem_t *p = 0, *fr = 0;
+ unsigned char pbuf[SIZEOF_PTR] = { 0 };
+ int left = 0;
+
+ switch (type(pat)) {
+ case NUM:
+ {
+ cnum pn = c_num(pat, self);
+ unsigned char *fill = pbuf + sizeof (pbuf);
+
+ if (pn < 0) {
+ left = 1;
+ pn = -pn;
+ }
+
+ do {
+ *--fill = pn & 0xff;
+ pn >>= 8;
+ } while (fill > pbuf && pn);
+
+ pl = pbuf + sizeof(pbuf) - fill;
+ p = fill;;
+ }
+ break;
+ case BGNUM:
+ {
+ if (minusp(pat)) {
+ left = 1;
+ pat = neg(pat);
+ }
+
+ {
+ mp_int *m = mp(pat);
+ pl = mp_unsigned_bin_size(m);
+ p = fr = chk_malloc(pl);
+ mp_to_unsigned_bin(m, p);
+ }
+ }
+ break;
+ case BUF:
+ {
+ struct buf *pb = buf_handle(pat, self);
+ p = pb->data;
+ pl = c_unum(pb->len, self);
+ }
+ break;
+ default:
+ unsup_obj(self, pat);
+ }
+
+ {
+ val nbuf = make_ubuf(l);
+ struct buf *nbh = buf_handle(nbuf, self);
+ ucnum i, j;
+
+ if (left) {
+ for (i = 0, j = 0; i < l; i++) {
+ nbh->data[i] = b->data[i] ^ p[j++];
+ if (j >= pl)
+ j = 0;
+ }
+ } else {
+ for (i = l - 1, j = pl; i != convert(ucnum, -1); --i) {
+ nbh->data[i] = b->data[i] ^ p[--j];
+ if (j == 0)
+ j = pl;
+ }
+ }
+
+ free(fr);
+ gc_hint(pat);
+ return nbuf;
+ }
+}
+
void buf_init(void)
{
reg_fun(intern(lit("make-buf"), user_package), func_n3o(make_buf, 1));
@@ -2019,6 +2099,7 @@ void buf_init(void)
reg_fun(intern(lit("buf-zero-p"), user_package), func_n1(buf_zero_p));
reg_fun(intern(lit("buf-count-ones"), user_package), func_n1(buf_count_ones));
reg_fun(intern(lit("buf-binary-width"), user_package), func_n1(buf_binary_width));
+ reg_fun(intern(lit("buf-xor-pattern"), user_package), func_n2(buf_xor_pattern));
fill_stream_ops(&buf_strm_ops);
}
diff --git a/buf.h b/buf.h
index c3c0fb29..fa3fbbcb 100644
--- a/buf.h
+++ b/buf.h
@@ -137,5 +137,6 @@ val buf_bit(val buf, val bit);
val buf_zero_p(val buf);
val buf_count_ones(val buf);
val buf_binary_width(val buf);
+val buf_xor_pattern(val buf, val pat);
void buf_init(void);
diff --git a/lib.c b/lib.c
index 8be3f708..5916e1c6 100644
--- a/lib.c
+++ b/lib.c
@@ -410,7 +410,7 @@ static val seq_iterable(seq_info_t si)
return nil;
}
-static void NORETURN unsup_obj(val self, val obj)
+NORETURN void unsup_obj(val self, val obj)
{
uw_throwf(type_error_s, lit("~a: unsupported object ~s"), self, obj, nao);
abort();
diff --git a/lib.h b/lib.h
index 614263de..2e416dcd 100644
--- a/lib.h
+++ b/lib.h
@@ -796,6 +796,7 @@ INLINE val type_check(val self, val obj, type_t typecode)
throw_mismatch(self, obj, typecode);
return t;
}
+NORETURN void unsup_obj(val self, val obj);
val car(val cons);
val cdr(val cons);
INLINE val us_car(val cons) { return cons->c.car; }
diff --git a/tests/012/buf.tl b/tests/012/buf.tl
index 128b3566..3dfdabc6 100644
--- a/tests/012/buf.tl
+++ b/tests/012/buf.tl
@@ -564,3 +564,14 @@
(mvtest
(buf-binary-width (buf-ash #b'01' i)) (succ i)
(width (uint-buf (buf-ash #b'01' i))) (succ i)))
+
+(mtest
+ (buf-xor-pattern #b'' 0) #b''
+ (buf-xor-pattern #b'00000000000000' #xcafe13) #b'13cafe13cafe13'
+ (buf-xor-pattern #b'00000000000000' #x-cafe13) #b'cafe13cafe13ca'
+ (buf-xor-pattern #b'aa5500' 255) #b'55aaff'
+ (buf-xor-pattern #b'ff550000ff' #b'ff00') #b'ffaa00ffff'
+ (buf-xor-pattern #b'0000000000000000 00000000000000' #x1122334455667788)
+ #b'2233445566778811 22334455667788'
+ (buf-xor-pattern #b'0000000000000000 00000000000000' #x-1122334455667788)
+ #b'1122334455667788 11223344556677')
diff --git a/txr.1 b/txr.1
index 5f3dc45f..54c9cee3 100644
--- a/txr.1
+++ b/txr.1
@@ -30515,6 +30515,81 @@ The following equivalence holds:
(buf-binary-width b) <--> (width (uint-buf b))
.brev
+.coNP Function @ buf-xor-pattern
+.synb
+.mets (buf-xor-pattern < buf << pat )
+.syne
+.desc
+The
+.code buf-xor-pattern
+function calculates a new buffer of the same size as
+.metn buf ,
+whose contents are the result of an exclusive "or" operation between
+.meta buf
+and
+.metn pat .
+
+The
+.meta pat
+argument may be an integer or a buffer.
+
+If
+.meta pat
+is a negative integer, it specifies a left-aligned operation.
+In this case, the pattern is specified by the positive integer
+which is the additive inverse of the negative integer. If
+.meta pat
+is a buffer, the operation is always right-aligned.
+
+Left-aligned means that the the first byte of the buffer
+corresponds with the first byte of the pattern. Right
+aligned means that the last bytes of the buffer and pattern
+correspond.
+
+An integer is turned into a pattern by dividing the integer's
+binary representation into octets, in a big-endian orientation.
+For instance the integer
+.code #x3FEDA
+is turned into the octets , given in hexadecimal:
+.codn 03 ,
+.code FE
+and
+.codn DA .
+The pattern has only as many bytes are are required to
+represent the integer value. Thus a value in the range
+0 to 255 specifies a one-byte pattern, a value in the
+range 256 to 65535 a two-byte pattern and so forth.
+
+If the pattern has fewer bytes than
+.meta buf
+then it is repeated. Any repetition of the pattern
+which doesn't fit into the buffer length is truncated
+on the opposite side of the alignment mode: truncated
+on the left under right alignment and vice versa.
+
+.TP* Examples
+
+.verb
+ ;; empty input buffer maps to empty output buffer
+ (buf-xor-pattern #b'' 0) -> #b''
+
+ ;; right-aligned three-byte pattern
+ (buf-xor-pattern #b'00000000000000' #xcafe13)
+ --> #b'13cafe13cafe13'
+
+ ;; left-aligned three-byte pattern
+ (buf-xor-pattern #b'00000000000000' #x-cafe13)
+ --> #b'cafe13cafe13ca'
+
+ ;; one-byte pattern
+ (buf-xor-pattern #b'aa5500' 255)
+ --> #b'55aaff'
+
+ ;; buffer pattern
+ (buf-xor-pattern #b'ff550000ff' #b'ff00')
+ --> #b'ffaa00ffff'
+.brev
+
.coNP Functions @ buf-compress and @ buf-decompress
.synb
.mets (buf-compress < buf <> [ level ])