/* This code is hereby released to the public domain. ~aaaaaa123456789, 2016-01-02 */ #include #include #include #define multibyte_is_zero(operand, size) ((int) ( \ ((int) (size)) && \ !(*((const unsigned char *) (operand))) && \ !memcmp(operand, ((const unsigned char *) (operand)) + 1, ((int) (size)) - 1) \ )) #define multibyte_is_negative(operand, size) (((int) (((const unsigned char *) (operand))[((int) (size)) - 1])) & 0x80) void multibyte_op (unsigned char * result, const unsigned char * operand0, const unsigned char * operand1, int op, unsigned size) { /* every two bits of op determine what to do with some intermediate result: 00 = nothing, 01 = subtract, 10 = add, 11 = add w/ negated shift bits 31-30: (operand0 AND operand1) >> shift amount, bits 29-28: (operand0 OR operand1) >> shift amount, bits 27-26: (operand0 AND operand1) << shift amount, bits 25-24: (operand0 OR operand1) << shift amount bits 23-0 of op indicate shift amount operand0 defaults to 0 if null, operand1 defaults to -1 if null EXAMPLE VALUES OF OP: 0x80000000 = AND, 0x20000000 = OR, 0x60000000 = XOR, 0xa0000000 = addition 0x60000000 with operand1 set to NULL = NOT, 0x10000000 with operand0 set to NULL = negate (-x) 0x2300xxxx = rotate right by xxxx, 0x3200xxxx = rotate left by xxxx, 0x2000xxxx = shift right by xxxx, 0x0200xxxx = shift left by xxxx (set operand0 to NULL for rotations and shifts) */ if (!(size && result)) return; if (!(op & 0xff000000)) { memset(result, 0, size); return; } char * op0 = NULL; char * op1 = NULL; if (!operand0) operand0 = op0 = calloc(size, 1); if (!operand1) operand1 = op1 = memset(malloc(size), -1, size); unsigned char * temp_and = NULL; unsigned char * temp_or = NULL; if (op & 0xcc000000) temp_and = malloc(size); if (op & 0x33000000) temp_or = malloc(size); const unsigned char * p0 = operand0; const unsigned char * p1 = operand1; unsigned char * p2 = temp_and; unsigned char * p3 = temp_or; unsigned rem; for (rem = size; rem >= sizeof(uint_fast8_t); rem -= sizeof(uint_fast8_t)) { if (temp_and) { *((uint_fast8_t *) p2) = *((const uint_fast8_t *) p0) & *((const uint_fast8_t *) p1); p2 += sizeof(uint_fast8_t); } if (temp_or) { *((uint_fast8_t *) p3) = *((const uint_fast8_t *) p0) | *((const uint_fast8_t *) p1); p3 += sizeof(uint_fast8_t); } p0 += sizeof(uint_fast8_t); p1 += sizeof(uint_fast8_t); } for (; rem; rem --) { if (temp_and) *(p2 ++) = *p0 & *p1; if (temp_or) *(p3 ++) = *p0 | *p1; p0 ++; p1 ++; } free(op0); free(op1); int shift_amount = op & 0xffffff; if (shift_amount & 0x800000) shift_amount -= 0x1000000; shift_amount %= size << 3; if (shift_amount < 0) shift_amount += size << 3; unsigned char ** partials = calloc(sizeof(unsigned char *), 4); int inverted_shift_amount = (size << 3) - shift_amount; unsigned pending_shift_list = 0; int temp, pos; if (shift_amount) { if (op & 0xc0000000) { *partials = calloc(size, 1); temp = ((op & 0xc0000000) == 0xc0000000) ? inverted_shift_amount : shift_amount; memcpy(*partials, temp_and + (temp >> 3), size - (temp >> 3)); pending_shift_list |= temp & 7; } if (op & 0x30000000) { partials[1] = calloc(size, 1); temp = ((op & 0x30000000) == 0x30000000) ? inverted_shift_amount : shift_amount; memcpy(partials[1], temp_or + (temp >> 3), size - (temp >> 3)); pending_shift_list |= (temp & 7) << 3; } if (op & 0xc000000) { partials[2] = calloc(size, 1); temp = ((op & 0xc000000) == 0xc000000) ? inverted_shift_amount : shift_amount; memcpy(partials[2] + (temp >> 3), temp_and, size - (temp >> 3)); pending_shift_list |= (temp & 7) << 6; } if (op & 0x3000000) { partials[3] = calloc(size, 1); temp = ((op & 0x3000000) == 0x3000000) ? inverted_shift_amount : shift_amount; memcpy(partials[3] + (temp >> 3), temp_or, size - (temp >> 3)); pending_shift_list |= (temp & 7) << 9; } unsigned current_shift; for (current_shift = 0; current_shift < 4; pending_shift_list >>= 3, current_shift ++) { shift_amount = pending_shift_list & 7; if (!shift_amount) continue; temp = 0; if (current_shift & 2) for (pos = 0; pos < size; pos ++) { temp |= partials[current_shift][pos] << shift_amount; partials[current_shift][pos] = temp & 0xff; temp >>= 8; } else for (pos = size - 1; pos >= 0; pos --) { temp = (temp << 8) | partials[current_shift][pos]; partials[current_shift][pos] = (temp >> shift_amount) & 0xff; } } } else { if (op & 0xc0000000) *partials = memcpy(malloc(size), temp_and, size); if (op & 0x30000000) partials[1] = memcpy(malloc(size), temp_or, size); if (op & 0x0c000000) partials[2] = memcpy(malloc(size), temp_and, size); if (op & 0x03000000) partials[3] = memcpy(malloc(size), temp_or, size); } free(temp_and); free(temp_or); temp = 0; int cp; for (pos = 0; pos < size; pos ++) { for (cp = 0; cp < 4; cp ++) if (op & (1 << (31 - (cp << 1)))) temp += (int) partials[cp][pos]; else if (op & (1 << (30 - (cp << 1)))) temp -= (int) partials[cp][pos]; result[pos] = temp & 0xff; temp >>= 8; } for (cp = 0; cp < 4; cp ++) free(partials[cp]); free(partials); }