-
Notifications
You must be signed in to change notification settings - Fork 1
/
bitpacker.c
157 lines (139 loc) · 3.66 KB
/
bitpacker.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/* bitpacker
* pack a stream of 7-bit ascii into 8 bit bytes
* return pointer to packed stream
* unpack a stream of 8 bit bytes
* return pointer to unpacked stream
* return NULL on any problem
*/
/* This POC is freeware.
* There is no warranty or performance guarantee.
* Code may be modified, used, as desired.
* Attribution to author is appreciated.
*
* Copyright 2022 Peter Hyman, pete@peterhyman.com
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include "bitpacker.h"
/* used by functions */
#define SHL(p,n) (p << n)
#define SHR(p,n) (p >> n)
#define MASKBITS(p,n) (!n ? p & 1 : p & ((2 << n) - 1))
int bperr; /* global error */
char *bperrstr[]={"bitpacker: OK",
"bitpacker: No Input to (un)pack",
"bitpacker: Input not 7 bit ASCII",
"bitpacker: FATAL! Cannot allocate ram for (un)pack"}; /* global error strings */
BYTE * abitpack(const BYTE *in)
{
int outpos = 0, inpos = 0, prevbyte = 0, bitpos = 0;
int length;
BYTE *out;
if (!in) /* nothing passed */
{
bperr=BPENOIN;
return NULL;
}
length = strlen((char *)in);
if (length <= 0) /* 0 length or strlen error */
{
bperr=BPENOIN;
return NULL;
}
out=calloc(length, 1); /* allocate output string */
if (out == NULL) /* something very wrong */
{
bperr=BPENOOUT;
return NULL;
}
length--; /* make length 0-based */
do
{
if (in[inpos] & 0b10000000) /* can't bitpack because high order bit set */
{
bperr=BPE8BIT;
free(out); /* cleanup */
return NULL;
}
out[outpos] = SHL(in[inpos], (bitpos + 1)); /* shift current byte 1-7 bits */
if (bitpos > 0) /* if second or more time through, update prior byte */
{
out[prevbyte] |= SHR(in[inpos], (7 - bitpos)); /* with bit 6 or more */
}
if (bitpos == 6) /* unless it's the 7th byte or multiple */
{
if (inpos <= length)
out[outpos] |= in[++inpos];
bitpos = -1; /* reset */
}
prevbyte = outpos;
outpos++;
inpos++;
bitpos++;
} while (inpos <= length);
bperr=BPEOK;
return (out);
}
BYTE * abitunpack(const BYTE *in)
{
int outpos = 0, inpos = 0, bitpos = 0;
int length, outlength;
BYTE work;
BYTE *out;
if (!in) /* nothing passed */
{
bperr=BPENOIN;
return NULL;
}
length = strlen((char *)in); /* packed input length */
if (length <= 0) /* 0 length or strlen error */
{
bperr=BPENOIN;
return NULL;
}
/* to determine outlength for fewer than 8 bytes, we must look at
* the value of byte 7 or its multiples.
* if the value of byte 7, 14, 21, etc. is 0 or not If 0
* then there are 7 bytes to unpack. Any other value,
* is a byte 8 or multiple to unpack too.
*/
outlength = length;
if (length > 7)
outlength += (int) (length / 7); /* pad outlength accordingly */
if (length % 7) /* we may have an extra byte */
{
if (in[length-1] & 0b01111111) /* there's something in last packed byte */
++outlength;
}
length--; /* 0-based */
out=calloc(outlength, 1);
if (!out) /* something very wrong */
{
bperr=BPENOOUT;
return NULL;
}
outlength--; /* 0-based */
do
{
work = MASKBITS(in[inpos], bitpos); /* save high bit(s) of next byte */
out[outpos] |= SHR(in[inpos], (bitpos + 1)); /* shift current byte 1-7 bits */
if (bitpos < 6) /* update next byte */
{
if (outpos < outlength)
out[outpos+1] |= SHL(work, (6 - bitpos)); /* paste high order bits into next byte */
}
else if (bitpos == 6) /* unless it's the 7th byte or multiple */
{
if (inpos <= length) /* more to come? */
out[++outpos] = work; /* incrrement outpos and set for next 7 bytes of unpack */
bitpos = -1; /* reset */
}
outpos++;
inpos++;
bitpos++;
} while (inpos <= length);
bperr=BPEOK;
return (out);
}