summaryrefslogtreecommitdiffstats
path: root/buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'buf.c')
-rw-r--r--buf.c81
1 files changed, 81 insertions, 0 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);
}