|
|
|
@ -44,47 +44,58 @@ namespace qp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class Iter>
|
|
|
|
|
int fetch(Iter& curr, Iter end)
|
|
|
|
|
{
|
|
|
|
|
if(curr == end)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
const int ret = *curr;
|
|
|
|
|
++curr;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class OutIter, class OutIter2>
|
|
|
|
|
void copy_out(OutIter& out, OutIter2 out_end, char c)
|
|
|
|
|
{
|
|
|
|
|
if(out == out_end)
|
|
|
|
|
{
|
|
|
|
|
throw std::runtime_error("Output buffer for QP-decoding is too small.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = c;
|
|
|
|
|
++out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template<class InIter, class OutIter, class OutIter2>
|
|
|
|
|
void decode_iter(InIter begin, InIter end, OutIter& out, OutIter2 out_end)
|
|
|
|
|
{
|
|
|
|
|
InIter c = begin;
|
|
|
|
|
while(c != end)
|
|
|
|
|
InIter curr = begin;
|
|
|
|
|
while(curr != end)
|
|
|
|
|
{
|
|
|
|
|
const char ch = *c;
|
|
|
|
|
const char ch = fetch(curr, end);
|
|
|
|
|
if(ch=='=')
|
|
|
|
|
{
|
|
|
|
|
++c;
|
|
|
|
|
if(c==end) throw UnexpectedEnd{};
|
|
|
|
|
if(*c == '\r') // soft line break
|
|
|
|
|
{
|
|
|
|
|
++c;
|
|
|
|
|
if(c==end) throw UnexpectedEnd{};
|
|
|
|
|
const int first = fetch(curr, end);
|
|
|
|
|
const int second = fetch(curr, end);
|
|
|
|
|
|
|
|
|
|
if(*c == '\n') // CRLF sequence completed
|
|
|
|
|
{
|
|
|
|
|
++c;
|
|
|
|
|
continue; // Soft Line Break: just absorb and go on.
|
|
|
|
|
}else{
|
|
|
|
|
throw IllegalHexSequence{'\r', *c};
|
|
|
|
|
}
|
|
|
|
|
if(first == '\r' && second == '\n') // soft line break
|
|
|
|
|
{
|
|
|
|
|
continue; // Soft Line Break: just absorb and go on.
|
|
|
|
|
}
|
|
|
|
|
try{
|
|
|
|
|
copy_out(out, out_end, char(from_hex((char)first, (char)second)) );
|
|
|
|
|
}catch(const IllegalHexSequence& e)
|
|
|
|
|
{
|
|
|
|
|
copy_out(out, out_end, '=');
|
|
|
|
|
if(first>=0) copy_out(out, out_end, first);
|
|
|
|
|
if(second>=0) copy_out(out, out_end, second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char high = *c;
|
|
|
|
|
++c;
|
|
|
|
|
if(c==end) throw std::runtime_error("Unexpected end of qp-encoded string!");
|
|
|
|
|
|
|
|
|
|
const char low = *c;
|
|
|
|
|
if(out == out_end) throw std::runtime_error("Output buffer too small.");
|
|
|
|
|
|
|
|
|
|
*out = char(from_hex(high, low));
|
|
|
|
|
++out;
|
|
|
|
|
}else{
|
|
|
|
|
if(out == out_end) throw std::runtime_error("Output buffer too small.");
|
|
|
|
|
*out = ch;
|
|
|
|
|
++out;
|
|
|
|
|
copy_out(out, out_end, ch );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
++c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|