00001
00002
00003
00004
00005
00006
00007
#include <ctype.h>
00008
#include "wvbackslash.h"
00009
00010 static const char *
escapein =
"\a\b\f\n\r\t\v";
00011 static const char *
escapeout =
"abfnrtv";
00012
00013 static inline char tohex(
int digit,
char alphabase = (
'a' - 10))
00014 {
00015
return (digit < 10 ?
'0' : alphabase) + digit;
00016 }
00017
00018 static inline int fromhex(
char digit)
00019 {
00020
if (isdigit(digit))
00021
return digit -
'0';
00022
if (digit >=
'A' && digit <=
'F')
00023
return digit -
'A' + 10;
00024
if (digit >=
'a' && digit <=
'f')
00025
return digit -
'a' + 10;
00026
return -1;
00027 }
00028
00029 static inline int fromoctal(
char digit)
00030 {
00031
if (digit >=
'0' && digit <=
'7')
00032
return digit -
'0';
00033
return -1;
00034 }
00035
00036
00037
00038
00039 WvBackslashEncoder::WvBackslashEncoder(
WvStringParm _nasties) :
00040 nasties(_nasties)
00041 {
00042 }
00043
00044
00045 bool WvBackslashEncoder::_encode(
WvBuf &inbuf,
WvBuf &outbuf,
00046
bool flush)
00047 {
00048 size_t avail = outbuf.
free();
00049 size_t len;
00050
while ((len = inbuf.
optgettable()) != 0)
00051 {
00052
const unsigned char *datain = inbuf.
get(len);
00053
for (size_t i = 0; i < len; ++i)
00054 {
00055
int c = datain[i];
00056
00057
00058
if (avail < 1)
00059 { outbuf.
unget(len - i);
return ! flush; }
00060
const char *foundnasty = NULL;
00061
const char *foundspecial = NULL;
00062
if (c !=
'\0')
00063 {
00064 foundnasty = strchr(nasties.
cstr(), c);
00065
if (! foundnasty)
00066 {
00067 foundspecial = strchr(
escapein, c);
00068
if (! foundspecial && isprint(c))
00069 {
00070 outbuf.
putch(c);
00071 avail -= 1;
00072
continue;
00073 }
00074 }
00075 }
00076
00077
00078
if (avail < 2)
00079 { outbuf.
unget(len - i);
return ! flush; }
00080
if (foundnasty != NULL)
00081 {
00082 outbuf.
putch(
'\\');
00083 outbuf.
putch(c);
00084 avail -= 2;
00085
continue;
00086 }
00087
if (foundspecial != NULL)
00088 {
00089 outbuf.
putch(
'\\');
00090 outbuf.
putch(
escapeout[foundspecial -
escapein]);
00091 avail -= 2;
00092
continue;
00093 }
00094
00095
00096
if (avail < 4)
00097 { outbuf.
unget(len - i);
return ! flush; }
00098 outbuf.
put(
"\\x", 2);
00099 outbuf.
putch(
tohex(c >> 4));
00100 outbuf.
putch(
tohex(c & 15));
00101 avail -= 4;
00102 }
00103 }
00104
return true;
00105 }
00106
00107
00108 bool WvBackslashEncoder::_reset()
00109 {
00110
return true;
00111 }
00112
00113
00114
00115
00116 WvBackslashDecoder::WvBackslashDecoder() : tmpbuf(4)
00117 {
00118
_reset();
00119 }
00120
00121
00122 bool WvBackslashDecoder::_encode(
WvBuf &inbuf,
WvBuf &outbuf,
00123
bool flush)
00124 {
00125
if (outbuf.
free() == 0)
00126
return inbuf.
used() == 0;
00127
if (! flushtmpbuf(outbuf))
00128
return false;
00129
00130 size_t len;
00131
while ((len = inbuf.
optgettable()) != 0)
00132 {
00133
const unsigned char *datain = inbuf.
get(len);
00134
for (size_t i = 0; i < len; ++i)
00135 {
00136
int c = datain[i];
00137
00138
switch (state)
00139 {
00140
case Initial:
00141
if (c ==
'\\')
00142 state = Escape;
00143 tmpbuf.putch(c);
00144
break;
00145
00146
case Escape:
00147
if (c >=
'0' && c <=
'3')
00148 {
00149 tmpbuf.
unalloc(1);
00150 value = c -
'0';
00151 state = Octal1;
00152 }
00153
else if (c ==
'x')
00154 {
00155 tmpbuf.putch(c);
00156 state = Hex1;
00157 }
00158
else if (c ==
'\n')
00159 {
00160
00161 tmpbuf.
unalloc(1);
00162 tmpbuf.putch(
' ');
00163 state = Initial;
00164 }
00165
else
00166 {
00167
const char *found = strchr(
escapeout, c);
00168 tmpbuf.
unalloc(1);
00169
if (found != NULL)
00170 c =
escapein[found -
escapeout];
00171
00172 tmpbuf.putch(c);
00173 state = Initial;
00174 }
00175
break;
00176
00177
case Hex2:
00178
case Hex1: {
00179
int digit =
fromhex(c);
00180
if (digit >= 0)
00181 {
00182
if (state == Hex1)
00183 {
00184 tmpbuf.
unalloc(2);
00185 value = digit;
00186 state = Hex2;
00187 }
00188
else
00189 {
00190 value = (value << 4) | digit;
00191 state = Initial;
00192 }
00193 }
00194
else
00195 {
00196 i -= 1;
00197 state = Initial;
00198 }
00199
break;
00200 }
00201
00202
case Octal3:
00203
case Octal2:
00204
case Octal1: {
00205
int digit =
fromoctal(c);
00206
if (digit >= 0)
00207 {
00208 value = (value << 3) | digit;
00209
if (state != Octal3)
00210 state = State(state + 1);
00211
else
00212 state = Initial;
00213 }
00214
else
00215 {
00216 i -= 1;
00217 state = Initial;
00218 }
00219
break;
00220 }
00221 }
00222
00223 flushtmpbuf(outbuf);
00224
if (outbuf.
free() == 0)
00225 {
00226 inbuf.
unget(len - i);
00227
break;
00228 }
00229 }
00230 }
00231
if (flush)
00232 {
00233
if (inbuf.
used() != 0)
00234
return false;
00235 state = Initial;
00236
return flushtmpbuf(outbuf);
00237 }
00238
return true;
00239
00240 }
00241
00242
00243 bool WvBackslashDecoder::_reset()
00244 {
00245 state = Initial;
00246 value = -1;
00247 tmpbuf.
zap();
00248
return true;
00249 }
00250
00251
00252
bool WvBackslashDecoder::flushtmpbuf(
WvBuf &outbuf)
00253 {
00254
if (state != Initial)
00255
return true;
00256
00257
if (value != -1)
00258 {
00259 tmpbuf.putch(value);
00260 value = -1;
00261 }
00262
00263 size_t len = tmpbuf.
used();
00264
if (len == 0)
00265
return true;
00266 size_t avail = outbuf.
free();
00267
if (avail > len)
00268 avail = len;
00269 outbuf.
merge(tmpbuf, avail);
00270 len -= avail;
00271
if (len == 0)
00272 {
00273 tmpbuf.
zap();
00274
return true;
00275 }
00276
return false;
00277 }