diff options
Diffstat (limited to 'buf.c')
-rw-r--r-- | buf.c | 81 |
1 files changed, 81 insertions, 0 deletions
@@ -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); } |