//========================================================================== // Name: varicode.h // Purpose: Varicode encoded and decode functions // Created: Nov 24, 2012 // Authors: David Rowe // // To test: // $ gcc varicode.c -o varicode -DVARICODE_UNITTEST -Wall // $ ./varicode // // License: // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2.1, // as published by the Free Software Foundation. This program 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 this program; if not, see . // //========================================================================== #include #include #include #include #include #include "varicode.h" #include "varicode_table.h" #include "debug_alloc.h" /* output is an unpacked array of bits of maximum size max_out. Note unpacked arrays are a more suitable form for modulator input. Code 1 covers the entire ASCII char set. */ int varicode_encode1(short varicode_out[], char ascii_in[], int max_out, int n_in) { int n_out, index, n_zeros, v_len; unsigned short byte1, byte2, packed; char c; n_out = 0; while(n_in && (n_out < max_out)) { c = *ascii_in; if ((unsigned int)c >= 128) { c = ' '; } index = 2*(unsigned int)(c); assert(index <= 254); byte1 = varicode_table1[index]; byte2 = varicode_table1[index+1]; packed = (byte1 << 8) + byte2; //printf("n_in: %d ascii_in: %c index: %d packed 0x%x\n", n_in, *ascii_in, index, packed); ascii_in++; n_zeros = 0; v_len = 0; while ((n_zeros < 2) && (n_out < max_out) && (v_len <= VARICODE_MAX_BITS)) { if (packed & 0x8000) { *varicode_out = 1; n_zeros = 0; } else { *varicode_out = 0; n_zeros++; } //printf("packed: 0x%x *varicode_out: %d n_zeros: %d v_len: %d\n", packed, *varicode_out, n_zeros,v_len ); packed <<= 1; varicode_out++; n_out++; v_len++; } assert(v_len <= VARICODE_MAX_BITS); n_in--; } return n_out; } /* Code 2 covers a subset, but is more efficient that Code 1 (282 compared to 1315 bits on unittest) Unsupported characters are replaced by spaces. We encode/decode two bits at a time. */ int varicode_encode2(short varicode_out[], char ascii_in[], int max_out, int n_in) { int n_out, n_zeros, v_len, i; unsigned short packed; n_out = 0; while(n_in && (n_out < max_out)) { packed = varicode_table2[0]; // default to space if char not found // see if our character exists for(i=0; istate = 0; dec_states->n_zeros = 0; dec_states->v_len = 0; dec_states->packed = 0; dec_states->code_num = code_num; dec_states->n_in = 0; dec_states->in[0] = dec_states->in[1] = 0; } void varicode_set_code_num(struct VARICODE_DEC *dec_states, int code_num) { assert((code_num == 1) || (code_num == 2)); dec_states->code_num = code_num; } /* Code 1 decode function, accepts one bit at a time */ static int decode_one_bit(struct VARICODE_DEC *s, char *single_ascii, short varicode_in, int long_code) { int found=0, i; unsigned short byte1, byte2; //printf("decode_one_bit : state: %d varicode_in: %d packed: 0x%x n_zeros: %d\n", // s->state, varicode_in, s->packed, s->n_zeros); if (s->state == 0) { if (!varicode_in) return 0; else s->state = 1; } if (s->state == 1) { if (varicode_in) { s->packed |= (0x8000 >> s->v_len); s->n_zeros = 0; } else { s->n_zeros++; } s->v_len++; found = 0; /* end of character code */ if (s->n_zeros == 2) { if (s->v_len) { /* run thru table but note with bit errors we might not actually find a match */ byte1 = s->packed >> 8; //printf("looking for byte1 : 0x%x ... ", byte1); byte2 = s->packed & 0xff; for(i=0; i<128; i++) { if ((byte1 == varicode_table1[2*i]) && (byte2 == varicode_table1[2*i+1])) { found = 1; *single_ascii = i; } } } varicode_decode_init(s, s->code_num); } /* code can run too long if we have a bit error */ if (s->v_len > VARICODE_MAX_BITS) varicode_decode_init(s, s->code_num); } return found; } /* Code 2 decode function, accepts two bits at a time */ static int decode_two_bits(struct VARICODE_DEC *s, char *single_ascii, short varicode_in1, short varicode_in2) { int found=0, i; unsigned short byte1; if (s->state == 0) { if (!(varicode_in1 || varicode_in2)) return 0; else s->state = 1; } if (s->state == 1) { if (varicode_in1) s->packed |= (0x8000 >> s->v_len); if (varicode_in2) s->packed |= (0x4000 >> s->v_len); if (varicode_in1 || varicode_in2) s->n_zeros = 0; else s->n_zeros+=2; s->v_len+=2; found = 0; /* end of character code */ if (s->n_zeros == 2) { if (s->v_len) { /* run thru table but note with bit errors we might not actually find a match */ byte1 = s->packed >> 8; //printf("looking for byte1 : 0x%x ... ", byte1); for(i=0; icode_num); } /* code can run too long if we have a bit error */ if (s->v_len > VARICODE_MAX_BITS) varicode_decode_init(s, s->code_num); } return found; } int varicode_decode1(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { int output, n_out; char single_ascii = 0; n_out = 0; //printf("varicode_decode: n_in: %d\n", n_in); while(n_in && (n_out < max_out)) { output = decode_one_bit(dec_states, &single_ascii, varicode_in[0], 0); varicode_in++; n_in--; if (output) { *ascii_out++ = single_ascii; n_out++; } } return n_out; } int varicode_decode2(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { int output, n_out; char single_ascii = 0; n_out = 0; //printf("varicode_decode2: n_in: %d varicode_in[0] %d dec_states->n_in: %d\n", n_in, varicode_in[0], dec_states->n_in); //printf("%d ", varicode_in[0]); while(n_in && (n_out < max_out)) { // keep two bit buffer so we can process two at a time dec_states->in[0] = dec_states->in[1]; dec_states->in[1] = varicode_in[0]; dec_states->n_in++; varicode_in++; n_in--; if (dec_states->n_in == 2) { output = decode_two_bits(dec_states, &single_ascii, dec_states->in[0], dec_states->in[1]); dec_states->n_in = 0; if (output) { //printf(" output: %d single_ascii: 0x%x %c\n", output, (int)single_ascii, single_ascii); *ascii_out++ = single_ascii; n_out++; } } } return n_out; } int varicode_decode(struct VARICODE_DEC *dec_states, char ascii_out[], short varicode_in[], int max_out, int n_in) { if (dec_states->code_num == 1) return varicode_decode1(dec_states, ascii_out, varicode_in, max_out, n_in); else return varicode_decode2(dec_states, ascii_out, varicode_in, max_out, n_in); } #ifdef VARICODE_UNITTEST void test_varicode(int code_num) { char *ascii_in; short *varicode; int i, n_varicode_bits_out, n_ascii_chars_out, length, half, n_out, j, len; char *ascii_out; struct VARICODE_DEC dec_states; if (code_num == 1) { printf("long code:\n"); length = sizeof(varicode_table1)/2; } else { printf("short code:\n"); length = sizeof(varicode_table2)/2; } //length = 10; ascii_in = (char*)MALLOC(length); varicode = (short*)MALLOC(VARICODE_MAX_BITS*sizeof(short)*length); ascii_out = (char*)MALLOC(length); // 1. test all Varicode codes ------------------------------------------------------------- if (code_num == 1) { for(i=0; i