mirror of
				https://github.com/RfidResearchGroup/proxmark3.git
				synced 2025-11-01 00:46:39 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			1215 lines
		
	
	
	
		
			41 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1215 lines
		
	
	
	
		
			41 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* poly.c
 | |
|  * Greg Cook, 23/Feb/2019
 | |
|  */
 | |
| 
 | |
| /* CRC RevEng: arbitrary-precision CRC calculator and algorithm finder
 | |
|  * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018,
 | |
|  * 2019  Gregory Cook
 | |
|  *
 | |
|  * This file is part of CRC RevEng.
 | |
|  *
 | |
|  * CRC RevEng is free software: you can redistribute it and/or modify
 | |
|  * it under the terms of the GNU General Public License as published by
 | |
|  * the Free Software Foundation, either version 3 of the License, or
 | |
|  * (at your option) any later version.
 | |
|  *
 | |
|  * CRC RevEng is distributed in the hope that it will be useful,
 | |
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
|  * GNU General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU General Public License
 | |
|  * along with CRC RevEng.  If not, see <https://www.gnu.org/licenses/>.
 | |
|  */
 | |
| 
 | |
| /* 2017-11-28: added braces, redundant statement skipped in prev()
 | |
|  * 2016-06-27: pcmp() shortcut returns 0 when pointers identical
 | |
|  * 2015-07-29: discard leading $, &, 0x from argument to strtop()
 | |
|  * 2015-04-03: added direct mode to strtop()
 | |
|  * 2014-01-11: added LOFS(), RNDUP()
 | |
|  * 2013-09-16: SIZE(), IDX(), OFS() macros bitshift if BMP_POF2
 | |
|  * 2013-02-07: conditional non-2^n fix, pmpar() return mask constant type
 | |
|  * 2013-01-17: fixed pfirst(), plast() for non-2^n BMP_BIT
 | |
|  * 2012-07-16: added pident()
 | |
|  * 2012-05-23: added pmpar()
 | |
|  * 2012-03-03: internal lookup tables stored better
 | |
|  * 2012-03-02: fixed full-width masking in filtop()
 | |
|  * 2011-09-06: added prevch()
 | |
|  * 2011-08-27: fixed zero test in piter()
 | |
|  * 2011-01-17: fixed ANSI C warnings, uses bmp_t type
 | |
|  * 2011-01-15: palloc() and praloc() gracefully handle lengths slightly
 | |
|  *         less than ULONG_MAX
 | |
|  * 2011-01-15: strtop() error on invalid argument. pkchop() special case
 | |
|  *         when argument all zeroes
 | |
|  * 2011-01-14: added pkchop()
 | |
|  * 2011-01-04: fixed bogus final length calculation in wide pcrc()
 | |
|  * 2011-01-02: faster, more robust prcp()
 | |
|  * 2011-01-01: commented functions, full const declarations, all-LUT rev()
 | |
|  * 2010-12-26: renamed CRC RevEng
 | |
|  * 2010-12-18: removed pmods(), finished pcrc(), added piter()
 | |
|  * 2010-12-17: roughed out pcrc(). difficult, etiam aberat musa heri :(
 | |
|  * 2010-12-15: added psnorm(), psncmp(); optimised pnorm(); fix to praloc()
 | |
|  * 2010-12-14: strtop() resets count between passes
 | |
|  * 2010-12-12: added pright()
 | |
|  * 2010-12-11: filtop won't read more than length bits
 | |
|  * 2010-12-10: finished filtop. 26 public functions
 | |
|  * 2010-12-05: finished strtop, pxsubs; unit tests
 | |
|  * 2010-12-02: project started
 | |
|  */
 | |
| 
 | |
| /* Note: WELL-FORMED poly_t objects have a valid bitmap pointer pointing
 | |
|  * to a malloc()-ed array of at least as many bits as stated in its
 | |
|  * length field.  Any poly_t with a length of 0 is also a WELL-FORMED
 | |
|  * poly_t (whatever value the bitmap pointer has.)
 | |
|  * All poly_t objects passed to and from functions must be WELL-FORMED
 | |
|  * unless otherwise stated.
 | |
|  *
 | |
|  * CLEAN (or CANONICAL) poly_t objects are WELL-FORMED objects in which
 | |
|  * all spare bits in the bitmap word containing the last bit are zero.
 | |
|  * (Any excess allocated words will not be accessed.)
 | |
|  *
 | |
|  * SEMI-NORMALISED poly_t objects are CLEAN objects in which the last
 | |
|  * bit, at position (length - 1), is one.
 | |
|  *
 | |
|  * NORMALISED poly_t objects are SEMI-NORMALISED objects in which the
 | |
|  * first bit is one.
 | |
|  *
 | |
|  * pfree() should be called on every poly_t object (including
 | |
|  * those returned by functions) after its last use.
 | |
|  * As always, free() should be called on every malloc()-ed string after
 | |
|  * its last use.
 | |
|  */
 | |
| 
 | |
| #include <limits.h>
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #include "reveng.h"
 | |
| 
 | |
| static bmp_t getwrd(const poly_t poly, unsigned long iter);
 | |
| static bmp_t rev(bmp_t accu, int bits);
 | |
| static void prhex(char **spp, bmp_t bits, int flags, int bperhx);
 | |
| 
 | |
| static const poly_t pzero = PZERO;
 | |
| 
 | |
| /* word number (0..m-1) of var'th bit (0..n-1) */
 | |
| #if BMP_POF2 >= 5
 | |
| #  define IDX(var) ((var) >> BMP_POF2)
 | |
| #else
 | |
| #  define IDX(var) ((var) / BMP_BIT)
 | |
| #endif
 | |
| 
 | |
| /* size of polynomial with var bits */
 | |
| #if BMP_POF2 >= 5
 | |
| #  define SIZE(var) ((BMP_BIT - 1UL + (var)) >> BMP_POF2)
 | |
| #else
 | |
| #  define SIZE(var) ((BMP_BIT - 1UL + (var)) / BMP_BIT)
 | |
| #endif
 | |
| 
 | |
| /* polynomial length rounded up to BMP_BIT */
 | |
| #ifdef BMP_POF2
 | |
| #  define RNDUP(var) (~(BMP_BIT - 1UL) & (BMP_BIT - 1UL + (var)))
 | |
| #else
 | |
| #  define RNDUP(var) ((BMP_BIT - (var) % BMP_BIT) % BMP_BIT + (var))
 | |
| #endif
 | |
| 
 | |
| /* bit offset (0..BMP_BIT-1, 0 = LSB) of var'th bit (0..n-1) */
 | |
| #ifdef BMP_POF2
 | |
| #  define OFS(var) ((int) ((BMP_BIT - 1UL) & ~(var)))
 | |
| #else
 | |
| #  define OFS(var) ((int) (BMP_BIT - 1UL - (var) % BMP_BIT))
 | |
| #endif
 | |
| 
 | |
| /* bit offset (0..BMP_BIT-1, 0 = MSB) of var'th bit (0..n-1) */
 | |
| #ifdef BMP_POF2
 | |
| #  define LOFS(var) ((int) ((BMP_BIT - 1UL) & (var)))
 | |
| #else
 | |
| #  define LOFS(var) ((int) ((var) % BMP_BIT))
 | |
| #endif
 | |
| 
 | |
| poly_t
 | |
| filtop(FILE *input, unsigned long length, int flags, int bperhx) {
 | |
|     /* reads binary data from input into a poly_t until EOF or until
 | |
|      * length bits are read.  Characters are read until
 | |
|      * ceil(bperhx / CHAR_BIT) bits are collected; if P_LTLBYT is
 | |
|      * set in flags then the first character contains the LSB,
 | |
|      * otherwise the last one does.  The least significant bperhx
 | |
|      * bits are taken, reflected (if P_REFIN) and appended to the
 | |
|      * result, then more characters are read.  The maximum number of
 | |
|      * characters read is
 | |
|      *   floor(length / bperhx) * ceil(bperhx / * CHAR_BIT).
 | |
|      * The returned poly_t is CLEAN.
 | |
|      */
 | |
| 
 | |
|     bmp_t accu = BMP_C(0);
 | |
|     bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
 | |
|     unsigned long iter = 0UL, idx;
 | |
|     int cmask = (1 << CHAR_BIT) - 1, c;
 | |
|     int count = 0, ofs;
 | |
|     poly_t poly = PZERO;
 | |
|     if (bperhx == 0) return (poly);
 | |
| 
 | |
|     length -= length % bperhx;
 | |
|     palloc(&poly, length); /* >= 0 */
 | |
| 
 | |
|     while (iter < length && (c = fgetc(input)) != EOF) {
 | |
|         if (flags & P_LTLBYT)
 | |
|             accu |= (bmp_t)(c & cmask) << count;
 | |
|         else
 | |
|             accu = (accu << CHAR_BIT) | (bmp_t)(c & cmask);
 | |
|         count += CHAR_BIT;
 | |
|         if (count >= bperhx) {
 | |
|             /* the low bperhx bits of accu contain bits of the poly.*/
 | |
|             iter += bperhx;
 | |
|             count = 0;
 | |
|             if (flags & P_REFIN)
 | |
|                 accu = rev(accu, bperhx);
 | |
|             accu &= mask;
 | |
| 
 | |
|             /* iter >= bperhx > 0 */
 | |
|             idx = IDX(iter - 1UL);
 | |
|             ofs = OFS(iter - 1UL);
 | |
|             poly.bitmap[idx] |= accu << ofs;
 | |
|             if (ofs + bperhx > BMP_BIT) {
 | |
|                 poly.bitmap[idx - 1] |= accu >> (BMP_BIT - ofs);
 | |
|             }
 | |
|             accu = BMP_C(0); /* only needed for P_LTLBYT */
 | |
|         }
 | |
|     }
 | |
|     praloc(&poly, iter);
 | |
|     return (poly);
 | |
| }
 | |
| 
 | |
| poly_t
 | |
| strtop(const char *string, int flags, int bperhx) {
 | |
|     /* Converts a hex or character string to a poly_t.
 | |
|      * Each character is converted to a hex nibble yielding 4 bits
 | |
|      * unless P_DIRECT, when each character yields CHAR_BIT bits.
 | |
|      * Nibbles and characters are accumulated left-to-right
 | |
|      * unless P_DIRECT && P_LTLBYT, when they are accumulated
 | |
|      * right-to-left without reflection.
 | |
|      * As soon as at least bperhx bits are accumulated, the
 | |
|      * rightmost bperhx bits are reflected (if P_REFIN)
 | |
|      * and appended to the poly.  When !P_DIRECT:
 | |
|      * bperhx=8 reads hex nibbles in pairs
 | |
|      * bperhx=7 reads hex nibbles in pairs and discards
 | |
|      *   b3 of first nibble
 | |
|      * bperhx=4 reads hex nibbles singly
 | |
|      * bperhx=3 reads octal
 | |
|      * bperhx=1 reads longhand binary
 | |
|      * in theory if !P_REFIN, bperhx can be any multiple of 4
 | |
|      * with equal effect
 | |
|      * The returned poly_t is CLEAN.
 | |
|      */
 | |
| 
 | |
|     /* make two passes, one to determine the poly size
 | |
|      * one to populate the bitmap
 | |
|      */
 | |
|     unsigned long length = 1UL, idx;
 | |
|     bmp_t accu;
 | |
|     bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
 | |
|     int pass, count, ofs;
 | |
|     int cmask = (1 << CHAR_BIT) - 1, c;
 | |
|     const char *s;
 | |
| 
 | |
|     poly_t poly = PZERO;
 | |
|     if (bperhx > BMP_BIT || bperhx <= 0 || string == NULL || *string == '\0')
 | |
|         return (poly);
 | |
| 
 | |
|     if (~flags & P_DIRECT) {
 | |
|         if (*string == '$' || *string == '&')
 | |
|             ++string;
 | |
|         else if (*string == '0'
 | |
|                  && (string[1] == 'x' || string[1] == 'X'))
 | |
|             string += 2;
 | |
|     }
 | |
|     length = (*string != '\0');
 | |
| 
 | |
|     for (pass = 0; pass < 2 && length > 0UL; ++pass) {
 | |
|         s = string;
 | |
|         length = 0UL;
 | |
|         count = 0;
 | |
|         accu = BMP_C(0);
 | |
|         while ((c = *s++)) {
 | |
|             if (flags & P_DIRECT) {
 | |
|                 if (flags & P_LTLBYT)
 | |
|                     accu |= (bmp_t)(c & cmask) << count;
 | |
|                 else
 | |
|                     accu = (accu << CHAR_BIT) | (bmp_t)(c & cmask);
 | |
|                 count += CHAR_BIT;
 | |
|             } else {
 | |
|                 if (c == ' ' || c == '\t' || c == '\r' || c == '\n') continue;
 | |
|                 accu <<= 4;
 | |
|                 count += 4;
 | |
|                 switch (c) {
 | |
|                     case '0':
 | |
|                     case '1':
 | |
|                     case '2':
 | |
|                     case '3':
 | |
|                     case '4':
 | |
|                     case '5':
 | |
|                     case '6':
 | |
|                     case '7':
 | |
|                     case '8':
 | |
|                     case '9':
 | |
|                         accu |= (bmp_t) c - '0';
 | |
|                         break;
 | |
|                     case 'A':
 | |
|                     case 'a':
 | |
|                         accu |= BMP_C(0xa);
 | |
|                         break;
 | |
|                     case 'B':
 | |
|                     case 'b':
 | |
|                         accu |= BMP_C(0xb);
 | |
|                         break;
 | |
|                     case 'C':
 | |
|                     case 'c':
 | |
|                         accu |= BMP_C(0xc);
 | |
|                         break;
 | |
|                     case 'D':
 | |
|                     case 'd':
 | |
|                         accu |= BMP_C(0xd);
 | |
|                         break;
 | |
|                     case 'E':
 | |
|                     case 'e':
 | |
|                         accu |= BMP_C(0xe);
 | |
|                         break;
 | |
|                     case 'F':
 | |
|                     case 'f':
 | |
|                         accu |= BMP_C(0xf);
 | |
|                         break;
 | |
|                     default:
 | |
|                         uerror("invalid character in hexadecimal argument");
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (count >= bperhx) {
 | |
|                 /* the low bperhx bits of accu contain bits of the poly.
 | |
|                  * in pass 0, increment length by bperhx.
 | |
|                  * in pass 1, put the low bits of accu into the bitmap. */
 | |
|                 length += bperhx;
 | |
|                 count = 0;
 | |
|                 if (pass == 1) {
 | |
|                     if (flags & P_REFIN)
 | |
|                         accu = rev(accu, bperhx);
 | |
|                     accu &= mask;
 | |
| 
 | |
|                     /* length >= bperhx > 0 */
 | |
|                     idx = IDX(length - 1);
 | |
|                     ofs = OFS(length - 1);
 | |
|                     poly.bitmap[idx] |= accu << ofs;
 | |
|                     if (ofs + bperhx > BMP_BIT)
 | |
|                         poly.bitmap[idx - 1] |= accu >> (BMP_BIT - ofs);
 | |
|                     accu = BMP_C(0); /* only needed for P_LTLBYT */
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         if (pass == 0) palloc(&poly, length);
 | |
|     }
 | |
|     return (poly);
 | |
| }
 | |
| 
 | |
| char *
 | |
| ptostr(const poly_t poly, int flags, int bperhx) {
 | |
|     /* Returns a malloc()-ed string containing a hexadecimal
 | |
|      * representation of poly. See phxsubs().
 | |
|      */
 | |
|     return (pxsubs(poly, flags, bperhx, 0UL, poly.length));
 | |
| }
 | |
| 
 | |
| char *
 | |
| pxsubs(const poly_t poly, int flags, int bperhx, unsigned long start, unsigned long end) {
 | |
|     /* Returns a malloc()-ed string containing a hexadecimal
 | |
|      * representation of a portion of poly, from bit offset start to
 | |
|      * (end - 1) inclusive.  The output is grouped into words of
 | |
|      * bperhx bits each.  If P_RTJUST then the first word is padded
 | |
|      * with zeroes at the MSB end to make a whole number of words,
 | |
|      * otherwise the last word is padded at the LSB end.  After
 | |
|      * justification the bperhx bits of each word are reversed (if
 | |
|      * P_REFOUT) and printed as a hex sequence, with words
 | |
|      * optionally separated by spaces (P_SPACE).
 | |
|      * If end exceeds the length of poly then zero bits are appended
 | |
|      * to make up the difference, in which case poly must be CLEAN.
 | |
|      */
 | |
|     char *string, *sptr;
 | |
|     unsigned long size, iter;
 | |
|     bmp_t accu;
 | |
|     bmp_t mask = bperhx == BMP_BIT ? ~BMP_C(0) : (BMP_C(1) << bperhx) - BMP_C(1);
 | |
|     int cperhx, part;
 | |
| 
 | |
|     if (bperhx <= 0 || bperhx > BMP_BIT) return (NULL);
 | |
| 
 | |
|     if (start > poly.length) start = poly.length;
 | |
|     if (end > poly.length) end = poly.length;
 | |
|     if (end < start) end = start;
 | |
| 
 | |
|     cperhx = (bperhx + 3) >> 2;
 | |
|     if (flags & P_SPACE) ++cperhx;
 | |
| 
 | |
|     size = (end - start + bperhx - 1UL) / bperhx;
 | |
|     size *= cperhx;
 | |
|     if (!size || ~flags & P_SPACE) ++size; /* for trailing null */
 | |
| 
 | |
|     if (!(sptr = string = (char *) calloc(size, sizeof(char))))
 | |
|         uerror("cannot allocate memory for string");
 | |
| 
 | |
|     size = end - start;
 | |
|     part = (int) size % bperhx;
 | |
|     if (part && flags & P_RTJUST) {
 | |
|         iter = start + part;
 | |
|         accu = getwrd(poly, iter - 1UL) & ((BMP_C(1) << part) - BMP_C(1));
 | |
|         if (flags & P_REFOUT)
 | |
|             /* best to reverse over bperhx rather than part, I think
 | |
|              * e.g. converting a 7-bit poly to 8-bit little-endian hex
 | |
|              */
 | |
|             accu = rev(accu, bperhx);
 | |
|         prhex(&sptr, accu, flags, bperhx);
 | |
|         if (flags & P_SPACE && size > iter) *sptr++ = ' ';
 | |
|     } else {
 | |
|         iter = start;
 | |
|     }
 | |
| 
 | |
|     while ((iter += bperhx) <= end) {
 | |
|         accu = getwrd(poly, iter - 1UL) & mask;
 | |
|         if (flags & P_REFOUT)
 | |
|             accu = rev(accu, bperhx);
 | |
|         prhex(&sptr, accu, flags, bperhx);
 | |
|         if (flags & P_SPACE && size > iter) *sptr++ = ' ';
 | |
|     }
 | |
| 
 | |
|     if (part && ~flags & P_RTJUST) {
 | |
|         accu = getwrd(poly, end - 1UL);
 | |
|         if (flags & P_REFOUT)
 | |
|             accu = rev(accu, part);
 | |
|         else
 | |
|             accu = accu << (bperhx - part) & mask;
 | |
|         prhex(&sptr, accu, flags, bperhx);
 | |
|     }
 | |
|     *sptr = '\0';
 | |
|     return (string);
 | |
| }
 | |
| 
 | |
| poly_t
 | |
| pclone(const poly_t poly) {
 | |
|     /* Returns a freestanding copy of poly.  Does not clean poly or
 | |
|      * the result.
 | |
|      */
 | |
|     poly_t clone = PZERO;
 | |
| 
 | |
|     pcpy(&clone, poly);
 | |
|     return (clone);
 | |
| }
 | |
| 
 | |
| void
 | |
| pcpy(poly_t *dest, const poly_t src) {
 | |
|     /* Assigns (copies) src into dest.  Does not clean src or dest.
 | |
|      */
 | |
|     unsigned long iter, idx;
 | |
| 
 | |
|     praloc(dest, src.length);
 | |
|     for (iter = 0UL, idx = 0UL; iter < src.length; iter += BMP_BIT, ++idx)
 | |
|         dest->bitmap[idx] = src.bitmap[idx];
 | |
| }
 | |
| 
 | |
| void
 | |
| pcanon(poly_t *poly) {
 | |
|     /* Converts poly into a CLEAN object by freeing unused bitmap words
 | |
|      * and clearing any bits in the last word beyond the last bit.
 | |
|      * The length field has absolute priority over the contents of the bitmap.
 | |
|      * Canonicalisation differs from normalisation in that leading and trailing
 | |
|      * zero terms are significant and preserved.
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
|     praloc(poly, poly->length);
 | |
| }
 | |
| 
 | |
| void
 | |
| pnorm(poly_t *poly) {
 | |
|     /* Converts poly into a NORMALISED object by removing leading
 | |
|      * and trailing zeroes, so that the polynomial starts and ends
 | |
|      * with significant terms.
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
|     unsigned long first;
 | |
| 
 | |
|     /* call pcanon() here so pfirst() and plast() return the correct
 | |
|      * results
 | |
|      */
 | |
|     pcanon(poly);
 | |
|     first = pfirst(*poly);
 | |
|     if (first)
 | |
|         pshift(poly, *poly, 0UL, first, plast(*poly), 0UL);
 | |
|     else
 | |
|         praloc(poly, plast(*poly));
 | |
| }
 | |
| 
 | |
| void
 | |
| psnorm(poly_t *poly) {
 | |
|     /* Converts poly into a SEMI-NORMALISED object by removing
 | |
|      * trailing zeroes, so that the polynomial ends with a
 | |
|      * significant term.
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
| 
 | |
|     /* call pcanon() here so plast() returns the correct result */
 | |
|     pcanon(poly);
 | |
|     praloc(poly, plast(*poly));
 | |
| }
 | |
| 
 | |
| void
 | |
| pchop(poly_t *poly) {
 | |
|     /* Normalise poly, then chop off the highest significant term
 | |
|      * (produces a SEMI-NORMALISED object).  poly becomes a suitable
 | |
|      * divisor for pcrc().
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
| 
 | |
|     /* call pcanon() here so pfirst() and plast() return correct
 | |
|      * results
 | |
|      */
 | |
|     pcanon(poly);
 | |
|     pshift(poly, *poly, 0UL, pfirst(*poly) + 1UL, plast(*poly), 0UL);
 | |
| }
 | |
| 
 | |
| void
 | |
| pkchop(poly_t *poly) {
 | |
|     /* Convert poly from Koopman notation to chopped form (produces
 | |
|      * a SEMI-NORMALISED object).  poly becomes a suitable divisor
 | |
|      * for pcrc().
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
|     unsigned long first;
 | |
| 
 | |
|     /* call pcanon() here so pfirst() returns the correct result */
 | |
|     pcanon(poly);
 | |
|     first = pfirst(*poly);
 | |
|     if (first >= poly->length) {
 | |
|         pfree(poly);
 | |
|         return;
 | |
|     }
 | |
|     pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL);
 | |
|     piter(poly);
 | |
| }
 | |
| 
 | |
| unsigned long
 | |
| plen(const poly_t poly) {
 | |
|     /* Return length of polynomial.
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      */
 | |
|     return (poly.length);
 | |
| }
 | |
| 
 | |
| int
 | |
| pcmp(const poly_t *a, const poly_t *b) {
 | |
|     /* Compares poly_t objects for identical sizes and contents.
 | |
|      * a and b must be CLEAN.
 | |
|      * Defines a total order relation for sorting, etc. although
 | |
|      * mathematically, polynomials of equal degree are no greater or
 | |
|      * less than one another.
 | |
|      */
 | |
|     unsigned long iter;
 | |
|     bmp_t *aptr, *bptr;
 | |
| 
 | |
|     if (!a || !b) return (!b - !a);
 | |
|     if (a->length < b->length) return (-1);
 | |
|     if (a->length > b->length) return (1);
 | |
|     aptr = a->bitmap;
 | |
|     bptr = b->bitmap;
 | |
|     if (aptr == bptr)
 | |
|         return (0);
 | |
|     for (iter = 0UL; iter < a->length; iter += BMP_BIT) {
 | |
|         if (*aptr < *bptr)
 | |
|             return (-1);
 | |
|         if (*aptr++ > *bptr++)
 | |
|             return (1);
 | |
|     }
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| int
 | |
| psncmp(const poly_t *a, const poly_t *b) {
 | |
|     /* Compares polys for identical effect, i.e. as though the
 | |
|      * shorter poly were padded with zeroes to the length of the
 | |
|      * longer.
 | |
|      * a and b must still be CLEAN, therefore psncmp() is *not*
 | |
|      * identical to pcmp() on semi-normalised polys as psnorm()
 | |
|      * clears the slack space.
 | |
|      */
 | |
|     unsigned long length, iter, idx;
 | |
|     bmp_t aword, bword;
 | |
|     if (!a || !b) return (!b - !a);
 | |
|     length = (a->length > b->length) ? a->length : b->length;
 | |
|     for (iter = 0UL, idx = 0UL; iter < length; iter += BMP_BIT, ++idx) {
 | |
|         aword = (iter < a->length) ? a->bitmap[idx] : BMP_C(0);
 | |
|         bword = (iter < b->length) ? b->bitmap[idx] : BMP_C(0);
 | |
|         if (aword < bword)
 | |
|             return (-1);
 | |
|         if (aword > bword)
 | |
|             return (1);
 | |
|     }
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| ptst(const poly_t poly) {
 | |
|     /* Tests whether a polynomial equals zero.  Returns 0 if equal,
 | |
|      * a nonzero value otherwise.
 | |
|      * poly must be CLEAN.
 | |
|      */
 | |
|     unsigned long iter;
 | |
|     bmp_t *bptr;
 | |
|     if (!poly.bitmap) return (0);
 | |
|     for (iter = 0UL, bptr = poly.bitmap; iter < poly.length; iter += BMP_BIT)
 | |
|         if (*bptr++) return (1);
 | |
|     return (0);
 | |
| }
 | |
| 
 | |
| unsigned long
 | |
| pfirst(const poly_t poly) {
 | |
|     /* Returns the index of the first nonzero term in poly.  If none
 | |
|      * is found, returns the length of poly.
 | |
|      * poly must be CLEAN.
 | |
|      */
 | |
|     unsigned long idx = 0UL, size = SIZE(poly.length);
 | |
|     bmp_t accu = BMP_C(0); /* initialiser for Acorn C */
 | |
|     unsigned int probe = BMP_SUB, ofs = 0;
 | |
| 
 | |
|     while (idx < size && !(accu = poly.bitmap[idx])) ++idx;
 | |
|     if (idx >= size) return (poly.length);
 | |
|     while (probe) {
 | |
| #ifndef BMP_POF2
 | |
|         while ((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1;
 | |
| #endif
 | |
|         if (accu >> (ofs | probe)) ofs |= probe;
 | |
|         probe >>= 1;
 | |
|     }
 | |
| 
 | |
|     return (BMP_BIT - 1UL - ofs + idx * BMP_BIT);
 | |
| }
 | |
| 
 | |
| unsigned long
 | |
| plast(const poly_t poly) {
 | |
|     /* Returns 1 plus the index of the last nonzero term in poly.
 | |
|      * If none is found, returns zero.
 | |
|      * poly must be CLEAN.
 | |
|      */
 | |
|     unsigned long idx, size = SIZE(poly.length);
 | |
|     bmp_t accu;
 | |
|     unsigned int probe = BMP_SUB, ofs = 0;
 | |
| 
 | |
|     if (!poly.length) return (0UL);
 | |
|     idx = size - 1UL;
 | |
|     while (idx && !(accu = poly.bitmap[idx])) --idx;
 | |
|     if (!idx && !(accu = poly.bitmap[idx])) return (0UL);
 | |
|     /* now accu == poly.bitmap[idx] and contains last significant term */
 | |
|     while (probe) {
 | |
| #ifndef BMP_POF2
 | |
|         while ((ofs | probe) >= (unsigned int) BMP_BIT) probe >>= 1;
 | |
| #endif
 | |
|         if (accu << (ofs | probe)) ofs |= probe;
 | |
|         probe >>= 1;
 | |
|     }
 | |
| 
 | |
|     return (idx * BMP_BIT + ofs + 1UL);
 | |
| }
 | |
| 
 | |
| poly_t
 | |
| psubs(const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) {
 | |
|     poly_t dest = PZERO;
 | |
|     pshift(&dest, src, head, start, end, tail);
 | |
|     return (dest);
 | |
| }
 | |
| 
 | |
| void
 | |
| pright(poly_t *poly, unsigned long length) {
 | |
|     /* Trims or extends poly to length at the left edge, prepending
 | |
|      * zeroes if necessary.  Analogous to praloc() except the
 | |
|      * rightmost terms of poly are preserved.
 | |
|      * On entry, poly may or may not be WELL-FORMED.
 | |
|      * On exit, poly is CLEAN.
 | |
|      */
 | |
| 
 | |
|     if (length > poly->length)
 | |
|         pshift(poly, *poly, length - poly->length, 0UL, poly->length, 0UL);
 | |
|     else if (length < poly->length)
 | |
|         pshift(poly, *poly, 0UL, poly->length - length, poly->length, 0UL);
 | |
|     else
 | |
|         praloc(poly, poly->length);
 | |
| }
 | |
| 
 | |
| void
 | |
| pshift(poly_t *dest, const poly_t src, unsigned long head, unsigned long start, unsigned long end, unsigned long tail) {
 | |
|     /* copies bits start to end-1 of src to dest, plus the number of leading and trailing zeroes given by head and tail.
 | |
|      * end may exceed the length of src in which case more zeroes are appended.
 | |
|      * dest may point to src, in which case the poly is edited in place.
 | |
|      * src must be CLEAN.
 | |
|      * On exit, dest is CLEAN.
 | |
|      */
 | |
| 
 | |
|     unsigned long length, fulllength, size, fullsize, iter, idx, datidx;
 | |
|     /* condition inputs; end, head and tail may be any value */
 | |
|     if (end < start) end = start;
 | |
| 
 | |
|     length = end - start + head;
 | |
|     fulllength = length + tail;
 | |
|     if (fulllength > src.length)
 | |
|         praloc(dest, fulllength);
 | |
|     else
 | |
|         praloc(dest, src.length);
 | |
| 
 | |
|     /* number of words in new poly */
 | |
|     size = SIZE(length);
 | |
|     fullsize = SIZE(fulllength);
 | |
|     /* array index of first word ending up with source material */
 | |
|     datidx = IDX(head);
 | |
| 
 | |
|     if (head > start && end > start) {
 | |
|         /* shifting right, size > 0 */
 | |
|         /* index of the source bit ending up in the LSB of the last word
 | |
|          * size * BMP_BIT >= length > head > 0 */
 | |
|         iter = size * BMP_BIT - head - 1UL;
 | |
|         for (idx = size - 1UL; idx > datidx; iter -= BMP_BIT, --idx)
 | |
|             dest->bitmap[idx] = getwrd(src, iter);
 | |
|         dest->bitmap[idx] = getwrd(src, iter);
 | |
|         /* iter == size * BMP_BIT - head - 1 - BMP_BIT * (size - 1 - datidx)
 | |
|          *      == BMP_BIT * (size - size + 1 + datidx) - head - 1
 | |
|          *      == BMP_BIT * (1 + head / BMP_BIT) - head - 1
 | |
|          *      == BMP_BIT + head - head % BMP_BIT - head - 1
 | |
|          *      == BMP_BIT - head % BMP_BIT - 1
 | |
|          *      >= 0
 | |
|          */
 | |
|     } else if (head <= start) {
 | |
|         /* shifting left or copying */
 | |
|         /* index of the source bit ending up in the LSB of bitmap[idx] */
 | |
|         iter = start - head + BMP_BIT - 1UL;
 | |
|         for (idx = datidx; idx < size; iter += BMP_BIT, ++idx)
 | |
|             dest->bitmap[idx] = getwrd(src, iter);
 | |
|     }
 | |
| 
 | |
|     /* clear head */
 | |
|     for (idx = 0UL; idx < datidx; ++idx)
 | |
|         dest->bitmap[idx] = BMP_C(0);
 | |
|     if (size)
 | |
|         dest->bitmap[datidx] &= ~BMP_C(0) >> LOFS(head);
 | |
| 
 | |
|     /* clear tail */
 | |
|     if (LOFS(length))
 | |
|         dest->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length));
 | |
|     for (idx = size; idx < fullsize; ++idx)
 | |
|         dest->bitmap[idx] = BMP_C(0);
 | |
| 
 | |
|     /* call praloc to shrink poly if required */
 | |
|     if (dest->length > fulllength)
 | |
|         praloc(dest, fulllength);
 | |
| }
 | |
| 
 | |
| void
 | |
| ppaste(poly_t *dest, const poly_t src, unsigned long skip, unsigned long seek, unsigned long end, unsigned long fulllength) {
 | |
|     /* pastes terms of src, starting from skip, to positions seek to end-1 of dest
 | |
|      * then sets length of dest to fulllength (>= end)
 | |
|      * to paste n terms of src, give end = seek + n
 | |
|      * to truncate dest at end of paste, set fulllength = end
 | |
|      * to avoid truncating, set fulllength = plen(*dest)
 | |
|      * dest may point to src, in which case the poly is edited in place.
 | |
|      * src must be CLEAN in the case that the end is overrun.
 | |
|      * On exit, dest is CLEAN.
 | |
|      */
 | |
|     bmp_t mask;
 | |
|     unsigned long seekidx, endidx, iter;
 | |
|     int seekofs;
 | |
|     if (end < seek) end = seek;
 | |
|     if (fulllength < end) fulllength = end;
 | |
| 
 | |
|     /* expand dest if necessary. don't shrink as dest may be src */
 | |
|     if (fulllength > dest->length)
 | |
|         praloc(dest, fulllength);
 | |
|     seekidx = IDX(seek);
 | |
|     endidx = IDX(end);
 | |
|     seekofs = OFS(seek);
 | |
|     /* index of the source bit ending up in the LSB of the first modified word */
 | |
|     iter = skip + seekofs;
 | |
|     if (seekidx == endidx) {
 | |
|         /* paste affects one word (traps end = seek case) */
 | |
|         mask = ((BMP_C(1) << seekofs) - (BMP_C(1) << OFS(end))) << 1;
 | |
|         dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask);
 | |
|     } else if (seek > skip) {
 | |
|         /* shifting right */
 | |
|         /* index of the source bit ending up in the LSB of the last modified word */
 | |
|         iter += (endidx - seekidx) * BMP_BIT;
 | |
|         mask = ~BMP_C(0) >> LOFS(end);
 | |
|         dest->bitmap[endidx] = (dest->bitmap[endidx] & mask) | (getwrd(src, iter) & ~mask);
 | |
|         for (iter -= BMP_BIT, --endidx; endidx > seekidx; iter -= BMP_BIT, --endidx)
 | |
|             dest->bitmap[endidx] = getwrd(src, iter);
 | |
|         mask = ~BMP_C(0) >> LOFS(seek);
 | |
|         dest->bitmap[endidx] = (dest->bitmap[endidx] & ~mask) | (getwrd(src, iter) & mask);
 | |
|         /* iter == skip + seekofs + (endidx - seekidx) * BMP_BIT - BMP_BIT * (endidx - seekidx)
 | |
|          *      == skip + seekofs + BMP_BIT * (endidx - seekidx - endidx + seekidx)
 | |
|          *      == skip + seekofs
 | |
|          *      >= 0
 | |
|          */
 | |
|     } else {
 | |
|         /* shifting left or copying */
 | |
|         mask = ~BMP_C(0) >> LOFS(seek);
 | |
|         dest->bitmap[seekidx] = (dest->bitmap[seekidx] & ~mask) | (getwrd(src, iter) & mask);
 | |
|         for (iter += BMP_BIT, ++seekidx; seekidx < endidx; iter += BMP_BIT, ++seekidx)
 | |
|             dest->bitmap[seekidx] = getwrd(src, iter);
 | |
|         mask = ~BMP_C(0) >> LOFS(end);
 | |
|         dest->bitmap[seekidx] = (dest->bitmap[seekidx] & mask) | (getwrd(src, iter) & ~mask);
 | |
|     }
 | |
|     /* shrink poly if required */
 | |
|     if (dest->length > fulllength)
 | |
|         praloc(dest, fulllength);
 | |
| }
 | |
| 
 | |
| void
 | |
| pdiff(poly_t *dest, const poly_t src, unsigned long ofs) {
 | |
|     /* Subtract src from dest (modulo 2) at offset ofs.
 | |
|      * In modulo 2 arithmetic, subtraction is equivalent to addition
 | |
|      * We include an alias for those who wish to retain the distinction
 | |
|      * src and dest must be CLEAN.
 | |
|      */
 | |
|     psum(dest, src, ofs);
 | |
| }
 | |
| 
 | |
| void
 | |
| psum(poly_t *dest, const poly_t src, unsigned long ofs) {
 | |
|     /* Adds src to dest (modulo 2) at offset ofs.
 | |
|      * When ofs == dest->length, catenates src on to dest.
 | |
|      * src and dest must be CLEAN.
 | |
|      */
 | |
|     unsigned long fulllength, idx, iter, end;
 | |
| 
 | |
|     fulllength = ofs + src.length;
 | |
|     if (fulllength > dest->length)
 | |
|         praloc(dest, fulllength);
 | |
|     /* array index of first word in dest to be modified */
 | |
|     idx = IDX(ofs);
 | |
|     /* index of bit in src to be added to LSB of dest->bitmap[idx] */
 | |
|     iter = OFS(ofs);
 | |
|     /* stop value for iter */
 | |
|     end = BMP_BIT - 1UL + src.length;
 | |
|     for (; iter < end; iter += BMP_BIT, ++idx)
 | |
|         dest->bitmap[idx] ^= getwrd(src, iter);
 | |
| }
 | |
| 
 | |
| void
 | |
| prev(poly_t *poly) {
 | |
|     /* Reverse or reciprocate a polynomial.
 | |
|      * On exit, poly is CLEAN.
 | |
|      */
 | |
|     unsigned long leftidx = 0UL, rightidx = SIZE(poly->length);
 | |
|     unsigned long ofs = LOFS(BMP_BIT - LOFS(poly->length));
 | |
|     unsigned long fulllength = poly->length + ofs;
 | |
|     bmp_t accu;
 | |
| 
 | |
|     if (ofs) {
 | |
|         /* removable optimisation */
 | |
|         if (poly->length < (unsigned long) BMP_BIT) {
 | |
|             *poly->bitmap = rev(*poly->bitmap >> ofs, (int) poly->length) << ofs;
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         /* claim remaining bits of last word (as we use public function pshift()) */
 | |
|         poly->length = fulllength;
 | |
|     }
 | |
| 
 | |
|     /* reverse and swap words in the array, leaving it right-justified */
 | |
|     while (leftidx < rightidx) {
 | |
|         /* rightidx > 0 */
 | |
|         accu = rev(poly->bitmap[--rightidx], BMP_BIT);
 | |
|         poly->bitmap[rightidx] = rev(poly->bitmap[leftidx], BMP_BIT);
 | |
|         poly->bitmap[leftidx++] = accu;
 | |
|     }
 | |
|     /* shift polynomial to left edge if required */
 | |
|     if (ofs)
 | |
|         pshift(poly, *poly, 0UL, ofs, fulllength, 0UL);
 | |
| }
 | |
| 
 | |
| void
 | |
| prevch(poly_t *poly, int bperhx) {
 | |
|     /* Reverse each group of bperhx bits in a polynomial.
 | |
|      * Does not clean poly.
 | |
|      */
 | |
|     unsigned long iter = 0, idx, ofs;
 | |
|     bmp_t mask, accu;
 | |
| 
 | |
|     if (bperhx < 2 || bperhx > BMP_BIT)
 | |
|         return;
 | |
|     if (poly->length % bperhx)
 | |
|         praloc(poly, bperhx - (poly->length % bperhx) + poly->length);
 | |
|     mask = ~BMP_C(0) >> (BMP_BIT - bperhx);
 | |
|     for (iter = (unsigned long)(bperhx - 1); iter < poly->length; iter += bperhx) {
 | |
|         accu = getwrd(*poly, iter) & mask;
 | |
|         accu ^= rev(accu, bperhx);
 | |
|         idx = IDX(iter);
 | |
|         ofs = OFS(iter);
 | |
|         poly->bitmap[idx] ^= accu << ofs;
 | |
|         if (ofs + bperhx > (unsigned int) BMP_BIT)
 | |
|             /* (BMP_BIT - 1UL - (iter) % BMP_BIT) + bperhx > BMP_BIT
 | |
|              * (-1UL - (iter) % BMP_BIT) + bperhx > 0
 | |
|              * (- (iter % BMP_BIT)) + bperhx > 1
 | |
|              * - (iter % BMP_BIT) > 1 - bperhx
 | |
|              * iter % BMP_BIT < bperhx - 1, iter >= bperhx - 1
 | |
|              * iter >= BMP_BIT
 | |
|              * idx >= 1
 | |
|              */
 | |
|             poly->bitmap[idx - 1] ^= accu >> (BMP_BIT - ofs);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| prcp(poly_t *poly) {
 | |
|     /* Reciprocate a chopped polynomial.  Use prev() on whole
 | |
|      * polynomials.
 | |
|      * On exit, poly is SEMI-NORMALISED.
 | |
|      */
 | |
|     unsigned long first;
 | |
| 
 | |
|     praloc(poly, RNDUP(poly->length));
 | |
|     prev(poly);
 | |
|     first = pfirst(*poly);
 | |
|     if (first >= poly->length) {
 | |
|         pfree(poly);
 | |
|         return;
 | |
|     }
 | |
|     pshift(poly, *poly, 0UL, first + 1UL, poly->length, 1UL);
 | |
|     piter(poly);
 | |
| }
 | |
| 
 | |
| void
 | |
| pinv(poly_t *poly) {
 | |
|     /* Invert a polynomial, i.e. add 1 (modulo 2) to the coefficient of each term
 | |
|      * on exit, poly is CLEAN.
 | |
|      */
 | |
|     unsigned long idx, size = SIZE(poly->length);
 | |
| 
 | |
|     for (idx = 0UL; idx < size; ++idx)
 | |
|         poly->bitmap[idx] = ~poly->bitmap[idx];
 | |
|     if (LOFS(poly->length))
 | |
|         poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length));
 | |
| }
 | |
| 
 | |
| poly_t
 | |
| pmod(const poly_t dividend, const poly_t divisor) {
 | |
|     /* Divide dividend by normalised divisor and return the remainder
 | |
|      * This function generates a temporary 'chopped' divisor for pcrc()
 | |
|      * If calling repeatedly with a constant divisor, produce a chopped copy
 | |
|      * with pchop() and call pcrc() directly for higher efficiency.
 | |
|      * dividend and divisor must be CLEAN.
 | |
|      */
 | |
| 
 | |
|     /* perhaps generate an error if divisor is zero */
 | |
|     poly_t subdivisor = psubs(divisor, 0UL, pfirst(divisor) + 1UL, plast(divisor), 0UL);
 | |
|     poly_t result = pcrc(dividend, subdivisor, pzero, pzero, 0);
 | |
|     pfree(&subdivisor);
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| poly_t
 | |
| pcrc(const poly_t message, const poly_t divisor, const poly_t init, const poly_t xorout, int flags) {
 | |
|     /* Divide message by divisor and return the remainder.
 | |
|      * init is added to divisor, highest terms aligned, before
 | |
|      * division.
 | |
|      * xorout is added to the remainder, highest terms aligned.
 | |
|      * If P_MULXN is set in flags, message is multiplied by x^n
 | |
|      * (i.e. trailing zeroes equal to the CRC width are appended)
 | |
|      * before adding init and division.  Set P_MULXN for most CRC
 | |
|      * calculations.
 | |
|      * All inputs must be CLEAN.
 | |
|      * If all inputs are CLEAN, the returned poly_t will be CLEAN.
 | |
|      */
 | |
|     unsigned long max = 0UL, iter, ofs, resiter;
 | |
|     bmp_t probe, rem, dvsr, *rptr, *sptr;
 | |
|     const bmp_t *bptr, *eptr;
 | |
|     poly_t result = PZERO;
 | |
| 
 | |
|     if (flags & P_MULXN)
 | |
|         max = message.length;
 | |
|     else if (message.length > divisor.length)
 | |
|         max = message.length - divisor.length;
 | |
|     bptr = message.bitmap;
 | |
|     eptr = message.bitmap + SIZE(message.length);
 | |
|     probe = ~(~BMP_C(0) >> 1);
 | |
|     if (divisor.length <= (unsigned long) BMP_BIT
 | |
|             && init.length <= (unsigned long) BMP_BIT) {
 | |
|         rem = init.length ? *init.bitmap : BMP_C(0);
 | |
|         dvsr = divisor.length ? *divisor.bitmap : BMP_C(0);
 | |
|         for (iter = 0UL, ofs = 0UL; iter < max; ++iter, --ofs) {
 | |
|             if (!ofs) {
 | |
|                 ofs = BMP_BIT;
 | |
|                 rem ^= *bptr++;
 | |
|             }
 | |
|             if (rem & probe)
 | |
|                 rem = (rem << 1) ^ dvsr;
 | |
|             else
 | |
|                 rem <<= 1;
 | |
|         }
 | |
|         if (bptr < eptr)
 | |
|             /* max < message.length */
 | |
|             rem ^= *bptr >> OFS(BMP_BIT - 1UL + max);
 | |
|         if (init.length > max && init.length - max > divisor.length) {
 | |
|             palloc(&result, init.length - max);
 | |
|             *result.bitmap = rem;
 | |
|         } else if (divisor.length) {
 | |
|             palloc(&result, divisor.length);
 | |
|             *result.bitmap = rem;
 | |
|         }
 | |
|     } else {
 | |
|         /* allocate maximum size plus one word for shifted divisors and one word containing zero.
 | |
|          * This also ensures that result[1] exists
 | |
|          */
 | |
|         palloc(&result, (init.length > divisor.length ? init.length : divisor.length) + (unsigned long)(BMP_BIT << 1));
 | |
|         /*if there is content in init, there will be an extra word in result to clear it */
 | |
|         psum(&result, init, 0UL);
 | |
|         if (max)
 | |
|             *result.bitmap ^= *bptr++;
 | |
|         for (iter = 0UL, ofs = 0UL; iter < max; ++iter, probe >>= 1) {
 | |
|             if (!probe) {
 | |
|                 probe = ~(~BMP_C(0) >> 1);
 | |
|                 ofs = 0UL;
 | |
|                 sptr = rptr = result.bitmap;
 | |
|                 ++sptr;
 | |
|                 /* iter < max <= message.length, so bptr is valid
 | |
|                  * shift result one word to the left, splicing in a message word
 | |
|                  * and clearing the last active word
 | |
|                  */
 | |
|                 *rptr++ = *sptr++ ^ *bptr++;
 | |
|                 for (resiter = (unsigned long)(BMP_BIT << 1); resiter < result.length; resiter += BMP_BIT)
 | |
|                     * rptr++ = *sptr++;
 | |
|             }
 | |
|             ++ofs;
 | |
|             if (*result.bitmap & probe)
 | |
|                 psum(&result, divisor, ofs);
 | |
|         }
 | |
|         rptr = result.bitmap;
 | |
|         ++rptr;
 | |
|         while (bptr < eptr)
 | |
|             *rptr++ ^= *bptr++;
 | |
|         /* 0 <= ofs <= BMP_BIT, location of the first bit of the result */
 | |
|         pshift(&result, result, 0UL, ofs, (init.length > max + divisor.length ? init.length - max - divisor.length : 0UL) + divisor.length + ofs, 0UL);
 | |
|     }
 | |
| 
 | |
|     if (result.bitmap != NULL)
 | |
|         psum(&result, xorout, 0UL);
 | |
| 
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| int
 | |
| piter(poly_t *poly) {
 | |
|     /* Replace poly with the 'next' polynomial of equal length.
 | |
|      * Returns zero if the next polynomial is all zeroes, a nonzero
 | |
|      * value otherwise.
 | |
|      * Does not clean poly.
 | |
|      */
 | |
|     bmp_t *bptr;
 | |
|     if (!poly->length) return (0);
 | |
| 
 | |
|     bptr = poly->bitmap + IDX(poly->length - 1UL);
 | |
|     *bptr += BMP_C(1) << OFS(poly->length - 1UL);
 | |
|     while (bptr != poly->bitmap && !*bptr)
 | |
|         ++(*--bptr);
 | |
|     return (*bptr != BMP_C(0));
 | |
| }
 | |
| 
 | |
| void
 | |
| palloc(poly_t *poly, unsigned long length) {
 | |
|     /* Replaces poly with a CLEAN object of the specified length,
 | |
|      * consisting of all zeroes.
 | |
|      * It is safe to call with length = 0, in which case the object
 | |
|      * is freed.
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      * On exit, poly is CLEAN.
 | |
|      */
 | |
|     unsigned long size = SIZE(length);
 | |
| 
 | |
|     poly->length = 0UL;
 | |
|     free(poly->bitmap);
 | |
|     poly->bitmap = NULL;
 | |
|     if (!length) return;
 | |
|     if (!size)
 | |
|         size = IDX(length) + 1UL;
 | |
|     poly->bitmap = (bmp_t *) calloc(size, sizeof(bmp_t));
 | |
|     if (poly->bitmap) {
 | |
|         poly->length = length;
 | |
|     } else
 | |
|         uerror("cannot allocate memory for poly");
 | |
| }
 | |
| 
 | |
| void
 | |
| pfree(poly_t *poly) {
 | |
|     /* Frees poly's bitmap storage and sets poly equal to the empty
 | |
|      * polynomial (PZERO).
 | |
|      * poly may or may not be WELL-FORMED.
 | |
|      * On exit, poly is CLEAN.
 | |
|      */
 | |
| 
 | |
|     /* palloc(poly, 0UL); */
 | |
| 
 | |
|     poly->length = 0UL;
 | |
|     free(poly->bitmap);
 | |
|     poly->bitmap = NULL;
 | |
| }
 | |
| 
 | |
| void
 | |
| praloc(poly_t *poly, unsigned long length) {
 | |
|     /* Trims or extends poly to length at the right edge, appending
 | |
|      * zeroes if necessary.
 | |
|      * On entry, poly may or may not be WELL-FORMED.
 | |
|      * On exit, poly is CLEAN.
 | |
|      */
 | |
|     unsigned long oldsize, size = SIZE(length);
 | |
|     if (!poly) return;
 | |
|     if (!length) {
 | |
|         poly->length = 0UL;
 | |
|         free(poly->bitmap);
 | |
|         poly->bitmap = NULL;
 | |
|         return;
 | |
|     }
 | |
|     if (!size)
 | |
|         size = IDX(length) + 1UL;
 | |
|     if (!poly->bitmap)
 | |
|         poly->length = 0UL;
 | |
|     oldsize = SIZE(poly->length);
 | |
|     if (oldsize != size)
 | |
|         /* reallocate if array pointer is null or array resized */
 | |
|         poly->bitmap = (bmp_t *) realloc((void *)poly->bitmap, size * sizeof(bmp_t));
 | |
|     if (poly->bitmap) {
 | |
|         if (poly->length < length) {
 | |
|             /* poly->length >= 0, length > 0, size > 0.
 | |
|              * poly expanded. clear old last word and all new words
 | |
|              */
 | |
|             if (LOFS(poly->length))
 | |
|                 poly->bitmap[oldsize - 1UL] &= ~(~BMP_C(0) >> LOFS(poly->length));
 | |
|             while (oldsize < size)
 | |
|                 poly->bitmap[oldsize++] = BMP_C(0);
 | |
|         } else if (LOFS(length))
 | |
|             /* poly->length >= length > 0.
 | |
|              * poly shrunk. clear new last word
 | |
|              */
 | |
|             poly->bitmap[size - 1UL] &= ~(~BMP_C(0) >> LOFS(length));
 | |
|         poly->length = length;
 | |
|     } else
 | |
|         uerror("cannot reallocate memory for poly");
 | |
| }
 | |
| 
 | |
| int
 | |
| pmpar(const poly_t poly, const poly_t mask) {
 | |
|     /* Return even parity of poly masked with mask.
 | |
|      * Poly and mask must be CLEAN.
 | |
|      */
 | |
|     bmp_t res = BMP_C(0);
 | |
|     int i = BMP_SUB;
 | |
|     const bmp_t *pptr = poly.bitmap, *mptr = mask.bitmap;
 | |
|     const bmp_t *const pend = poly.bitmap + SIZE(poly.length);
 | |
|     const bmp_t *const mend = mask.bitmap + SIZE(mask.length);
 | |
| 
 | |
|     while (pptr < pend && mptr < mend)
 | |
|         res ^= *pptr++ & *mptr++;
 | |
|     do
 | |
|         res ^= res >> i;
 | |
|     while (i >>= 1);
 | |
| 
 | |
|     return ((int)(res & BMP_C(1)));
 | |
| }
 | |
| 
 | |
| int
 | |
| pident(const poly_t a, const poly_t b) {
 | |
|     /* Return nonzero if a and b have the same length
 | |
|      * and point to the same bitmap.
 | |
|      * a and b need not be CLEAN.
 | |
|      */
 | |
|     return (a.length == b.length && a.bitmap == b.bitmap);
 | |
| }
 | |
| 
 | |
| /* Private functions */
 | |
| 
 | |
| static bmp_t
 | |
| getwrd(const poly_t poly, unsigned long iter) {
 | |
|     /* Fetch unaligned word from poly where LSB of result is
 | |
|      * bit iter of the bitmap (counting from zero).  If iter exceeds
 | |
|      * the length of poly then zeroes are appended as necessary.
 | |
|      * Factored from ptostr().
 | |
|      * poly must be CLEAN.
 | |
|      */
 | |
|     bmp_t accu = BMP_C(0);
 | |
|     unsigned long idx, size;
 | |
|     int ofs;
 | |
| 
 | |
|     idx = IDX(iter);
 | |
|     ofs = OFS(iter);
 | |
|     size = SIZE(poly.length);
 | |
| 
 | |
|     if (idx < size)
 | |
|         accu |= poly.bitmap[idx] >> ofs;
 | |
|     if (idx && idx <= size && ofs > 0)
 | |
|         accu |= poly.bitmap[idx - 1UL] << (BMP_BIT - ofs);
 | |
|     return (accu);
 | |
| }
 | |
| 
 | |
| static bmp_t
 | |
| rev(bmp_t accu, int bits) {
 | |
|     /* Returns the bitmap word argument with the given number of
 | |
|      * least significant bits reversed and the rest cleared.
 | |
|      */
 | |
|     static const unsigned char revtab[256] = {
 | |
|         0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
 | |
|         0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
 | |
|         0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
 | |
|         0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
 | |
|         0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
 | |
|         0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
 | |
|         0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
 | |
|         0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
 | |
|         0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
 | |
|         0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
 | |
|         0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
 | |
|         0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
 | |
|         0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
 | |
|         0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
 | |
|         0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
 | |
|         0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
 | |
|         0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
 | |
|         0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
 | |
|         0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
 | |
|         0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
 | |
|         0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
 | |
|         0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
 | |
|         0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
 | |
|         0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
 | |
|         0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
 | |
|         0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
 | |
|         0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
 | |
|         0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
 | |
|         0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
 | |
|         0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
 | |
|         0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
 | |
|         0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
 | |
|     };
 | |
|     bmp_t result = BMP_C(0);
 | |
|     while (bits > 8) {
 | |
|         bits -= 8;
 | |
|         result = result << 8 | revtab[accu & 0xff];
 | |
|         accu >>= 8;
 | |
|     }
 | |
|     result = result << bits | (bmp_t)(revtab[accu & 0xff] >> (8 - bits));
 | |
|     return (result);
 | |
| }
 | |
| 
 | |
| static void
 | |
| prhex(char **spp, bmp_t bits, int flags, int bperhx) {
 | |
|     /* Appends a hexadecimal string representing the bperhx least
 | |
|      * significant bits of bits to an external string.
 | |
|      * spp points to a character pointer that in turn points to the
 | |
|      * end of a hex string being built.  prhex() advances this
 | |
|      * second pointer by the number of characters written.
 | |
|      * The unused MSBs of bits MUST be cleared.
 | |
|      * Set P_UPPER in flags to write A-F in uppercase.
 | |
|      */
 | |
|     static const char hex[] = "0123456789abcdef0123456789ABCDEF";
 | |
|     const int upper = ((flags & P_UPPER) ? 0x10 : 0);
 | |
|     while (bperhx > 0) {
 | |
|         bperhx -= ((bperhx + 3) & 3) + 1;
 | |
|         *(*spp)++ = hex[(bits >> bperhx & BMP_C(0xf)) | upper];
 | |
|     }
 | |
| }
 |