/**
* ======================== legal notice ======================
*
* File: Codec.cc
* Created: 21. Mai 2012, 14
* Author: Geronimo
* Project: libutil - base classes used by other libraries
*
* CMP - compound media player
*
* is a client/server mediaplayer intended to play any media from any workstation
* without the need to export or mount shares. cmps is an easy to use backend
* with a (ready to use) HTML-interface. Additionally the backend supports
* authentication via HTTP-digest authorization.
* cmpc is a client with vdr-like osd-menues.
*
* Copyright (c) 2012 Reinhard Mantey, some rights reserved!
* published under Creative Commons by-sa
* For details see http://creativecommons.org/licenses/by-sa/3.0/
*
* The cmp project's homepage is at http://projects.vdr-developer.org/projects/cmp
*
* --------------------------------------------------------------
*/
#include "Codec.h"
#include "util.h"
#include
#include
#include
#include
// --- Codec ------------------------------------------------------------------
static cHexEncoder * hexEncoder = NULL;
static cHexDecoder * hexDecoder = NULL;
cCodec::cCodec(const char *Table, char SpecialChar)
: translateTable(strdup(Table))
, keyChar(SpecialChar)
{
}
cCodec::~cCodec()
{
FREE(translateTable);
}
size_t cCodec::DecodeSequence(unsigned char *d, unsigned char *s)
{
*d = *s;
return 1;
}
// --- Encoder ----------------------------------------------------------------
cEncoder::cEncoder(char SpecialChar, const char *TrTable)
: cCodec(TrTable, SpecialChar)
{
}
cEncoder::~cEncoder()
{
}
char *cEncoder::Encode(const char *Source, size_t SourceLength)
{
if (!Source) return NULL;
if (!SourceLength) SourceLength = strlen(Source);
const unsigned char *s = (const unsigned char *)Source;
const unsigned char *last = (const unsigned char *)(Source + SourceLength);
char *rv = (char *)malloc(SourceLength * 3 + 1);
char *d = rv;
unsigned char c;
for (; s < last; ++s) {
c = *s;
if (c < 0x80 && (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~'))
*d++ = c;
else if (c == ' ')
*d++ = '+';
else {
*d++ = KeyChar();
*d++ = TranslateTable()[c >> 4];
*d++ = TranslateTable()[c & 0x0F];
}
}
*d = 0;
return rv;
}
// --- URLEncoder -------------------------------------------------------------
cURLEncoder::cURLEncoder()
: cEncoder('%')
{
}
cURLEncoder::~cURLEncoder()
{
}
// --- Decoder ----------------------------------------------------------------
cDecoder::cDecoder(char SpecialChar, const char *TrTable)
: cCodec(TrTable, SpecialChar)
{
}
cDecoder::~cDecoder()
{
}
char *cDecoder::Decode(const char *Source, size_t SourceLength)
{
if (!Source) return NULL;
if (!SourceLength) SourceLength = strlen(Source);
const unsigned char *s = (const unsigned char *)Source;
const unsigned char *last = (const unsigned char *)(Source + SourceLength);
char *rv = (char *)malloc(SourceLength + 1);
unsigned char *d = (unsigned char *) rv;
size_t seqLen;
for (; s < last; ++s) {
if (*s == KeyChar()) {
seqLen = DecodeSequence(d++, (unsigned char *) ++s);
s += seqLen;
}
else if (*s == '+') {
*d++ = ' ';
}
else {
*d++ = *s;
}
}
*d = 0;
return rv;
}
size_t cDecoder::DecodeSequence(unsigned char *d, unsigned char *s)
{
// just transform hex sequence back to character
unsigned char c = s[0] >= 'A' ? ((s[0] & 0xDF) - 'A') + 10 : (s[0] - '0');
c *= 16;
c += s[1] >= 'A' ? ((s[1] & 0xDF) - 'A') + 10 : (s[1] - '0');
*d = c;
return 1;
}
// --- URLDecoder -------------------------------------------------------------
cURLDecoder::cURLDecoder()
: cDecoder('%')
{
}
cURLDecoder::~cURLDecoder()
{
}
// --- HexEncoder -------------------------------------------------------------
cHexEncoder::cHexEncoder()
: cEncoder('#', "0123456789abcdef")
{
}
cHexEncoder::~cHexEncoder()
{
}
char* cHexEncoder::Encode(const unsigned char* Source, size_t SourceLength)
{
if (!SourceLength) SourceLength = strlen((const char *)Source);
const unsigned char *s = (const unsigned char *)Source;
char *rv = (char *)malloc(SourceLength * 3 + 1);
char *d = rv;
unsigned char c;
for (int i=0; i < 16; ++i, ++s) {
c = *s;
*d++ = TranslateTable()[c >> 4];
*d++ = TranslateTable()[c & 0x0F];
}
*d = 0;
return rv;
}
cHexEncoder * getHexEncoder(void) {
if (!hexEncoder) hexEncoder = new cHexEncoder();
return hexEncoder;
}
// --- HexDecoder -------------------------------------------------------------
cHexDecoder::cHexDecoder()
{
}
cHexDecoder::~cHexDecoder()
{
}
char* cHexDecoder::Decode(const char* Source, size_t SourceLength)
{
if (!Source) return NULL;
if (!SourceLength) SourceLength = strlen(Source);
const unsigned char *s = (const unsigned char *)Source;
const unsigned char *last = (const unsigned char *)(Source + SourceLength);
char *rv = (char *)malloc(SourceLength + 1);
unsigned char *d = (unsigned char *) rv;
unsigned char c0, c1;
for (; s < last; s += 2) {
c0 = toupper(s[0]);
c1 = c0 >= 'A' ? ((c0 & 0xDF) - 'A') + 10 : (c0 - '0');
c1 *= 16;
c0 = toupper(s[1]);
c1 = c0 >= 'A' ? ((c0 & 0xDF) - 'A') + 10 : (c0 - '0');
*d++ = c1;
}
*d = 0;
return rv;
}
cHexDecoder * getHexDecoder(void) {
if (!hexDecoder) hexDecoder = new cHexDecoder();
return hexDecoder;
}
void codecCleanUp(void) {
if (hexEncoder) {
delete hexEncoder;
hexEncoder = NULL;
}
if (hexDecoder) {
delete hexDecoder;
hexDecoder = NULL;
}
}