diff options
-rw-r--r-- | buf.c | 81 | ||||
-rw-r--r-- | buf.h | 1 | ||||
-rw-r--r-- | lib.c | 2 | ||||
-rw-r--r-- | lib.h | 1 | ||||
-rw-r--r-- | tests/012/buf.tl | 11 | ||||
-rw-r--r-- | txr.1 | 75 |
6 files changed, 170 insertions, 1 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); } @@ -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); @@ -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(); @@ -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') @@ -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 ]) |