diff options
Diffstat (limited to 'glcdskin/xml.c')
-rw-r--r-- | glcdskin/xml.c | 161 |
1 files changed, 126 insertions, 35 deletions
diff --git a/glcdskin/xml.c b/glcdskin/xml.c index ed29d11..a3ad976 100644 --- a/glcdskin/xml.c +++ b/glcdskin/xml.c @@ -15,32 +15,15 @@ #include <iostream> #include <fstream> +#include <string.h> +#include <stdlib.h> + #include "xml.h" +#include "../glcdgraphics/common.h" namespace GLCD { -std::string trim(const std::string & s) -{ - std::string::size_type start, end; - - start = 0; - while (start < s.length()) - { - if (!isspace(s[start])) - break; - start++; - } - end = s.length() - 1; - while (end >= 0) - { - if (!isspace(s[end])) - break; - end--; - } - return s.substr(start, end - start + 1); -} - enum { LOOK4START, // looking for first element start LOOK4TAG, // looking for element tag @@ -57,7 +40,7 @@ enum { INCLOSETAG, // reading closing tag }; -cXML::cXML(const std::string & file) +cXML::cXML(const std::string & file, const std::string sysCharset) : nodestartcb(NULL), nodeendcb(NULL), cdatacb(NULL), @@ -66,6 +49,18 @@ cXML::cXML(const std::string & file) { char * buffer; long size; + sysEncoding = sysCharset; + sysIsUTF8 = (sysEncoding == "UTF-8"); + if (!sysIsUTF8) { + // convert from utf-8 to system encoding + iconv_cd = iconv_open(sysEncoding.c_str(), "UTF-8"); + if (iconv_cd == (iconv_t) -1) { + syslog(LOG_ERR, "ERROR: system encoding %s is not supported\n", sysEncoding.c_str()); + iconv_cd = NULL; + } + } else { + iconv_cd = NULL; + } #if (__GNUC__ < 3) std::ifstream f(file.c_str(), std::ios::in | std::ios::binary | std::ios::ate); @@ -75,20 +70,24 @@ cXML::cXML(const std::string & file) if (!f.is_open()) { syslog(LOG_ERR, "ERROR: skin file %s not found\n", file.c_str()); - } - size = f.tellg(); + validFile = false; + } else { + validFile = true; + size = f.tellg(); #if (__GNUC__ < 3) - f.seekg(0, std::ios::beg); + f.seekg(0, std::ios::beg); #else - f.seekg(0, std::ios_base::beg); + f.seekg(0, std::ios_base::beg); #endif - buffer = new char[size]; - f.read(buffer, size); - f.close(); - data.assign(buffer, size); - delete[] buffer; + buffer = new char[size]; + f.read(buffer, size); + f.close(); + data.assign(buffer, size); + delete[] buffer; + } } +#if 0 cXML::cXML(const char * mem, unsigned int len) : nodestartcb(NULL), nodeendcb(NULL), @@ -98,6 +97,13 @@ cXML::cXML(const char * mem, unsigned int len) { data.assign(mem, len); } +#endif + +cXML::~cXML() +{ + if (iconv_cd != NULL) + iconv_close(iconv_cd); +} void cXML::SetNodeStartCB(XML_NODE_START_CB(cb)) { @@ -129,14 +135,29 @@ int cXML::Parse(void) int percent = 0; int last = 0; std::string::size_type len; + uint32_t c, c_tmp; + unsigned int i_old; + int l, char_size; + + if (!validFile) + return -1; state = LOOK4START; linenr = 1; skipping = false; len = data.length(); - for (std::string::size_type i = 0; i < len; i++) + + unsigned int i = 0; + while (i < (unsigned int)len) { - if (ReadChar(data[i]) != 0) + i_old = i; + encodedCharAdjustCounter(true, data, c_tmp, i); + char_size = (i - i_old) + 1; + c = 0; + for (l = 0 ; l < char_size; l++) + c += ( (0xFF & data[i_old + l]) << ( l << 3) ); + + if (ReadChar(c /*data[i]*/, char_size) != 0) return -1; if (progresscb) { @@ -147,6 +168,7 @@ int cXML::Parse(void) last = percent; } } + i++; } return 0; } @@ -156,8 +178,15 @@ bool cXML::IsTokenChar(bool start, int c) return isalpha(c) || c == '_' || (!start && isdigit(c)); } -int cXML::ReadChar(int c) +int cXML::ReadChar(unsigned int c, int char_size) { + // buffer for conversions (when conversion from utf8 to system encoding is required) + char convbufin[5]; + char convbufout[5]; + char* convbufinp = convbufin; + char* convbufoutp = convbufout; + size_t bufin_size, bufout_size, bufconverted; + // new line? if (c == '\n') linenr++; @@ -179,6 +208,46 @@ int cXML::ReadChar(int c) cdata.replace(pos, 4, ">"); else if (cdata.substr(pos, 5) == "&") cdata.replace(pos, 5, "&"); + else if (cdata.substr(pos, 2) == "&#") { + bool ishex = ((cdata.substr(pos+2, 1) == "x") || (cdata.substr(pos+2, 1) == "X") ); + size_t startpos = pos+2+((ishex)?1:0); + size_t endpos = cdata.find(';', startpos ); + if (endpos != std::string::npos) { + char* tempptr; + std::string charid = cdata.substr(startpos, endpos-startpos); + long val = strtol(charid.c_str(), &tempptr, (ishex) ? 16 : 10); + + if (tempptr != charid.c_str() && *tempptr == '\0') { + char encbuf[5]; size_t enclen = 0; + + if ( val <= 0x1F ) { + enclen = 0; // ignore control chars + } else if ( val <= 0x007F ) { + enclen = 1; + encbuf[0] = (char)(val & 0x7F); + } else if ( val <= 0x07FF ) { + enclen = 2; + encbuf[1] = (char)(( val & 0x003F) | 0x80); + encbuf[0] = (char)(( (val & 0x07C0) >> 6) | 0xC0); + } else if ( val <= 0xFFFF ) { + enclen = 3; + encbuf[2] = (char)(( val & 0x003F) | 0x80); + encbuf[1] = (char)(( (val & 0x0FC0) >> 6) | 0x80); + encbuf[0] = (char)(( (val & 0xF000) >> 12) | 0xE0); + } else if ( val <= 0x10FFFF ) { + enclen = 4; + encbuf[3] = (char)(( val & 0x003F) | 0x80); + encbuf[2] = (char)(( (val & 0x0FC0) >> 6) | 0x80); + encbuf[1] = (char)(( (val & 0x03F000 ) >> 12) | 0x80); + encbuf[0] = (char)(( (val & 0x1C0000 ) >> 18) | 0xF0); + } + encbuf[enclen] = '\0'; + if (enclen > 0) { + cdata.replace(pos, endpos-pos+1, encbuf); + } + } + } + } pos++; } if (!cdatacb(trim(cdata))) @@ -190,7 +259,29 @@ int cXML::ReadChar(int c) state = LOOK4TAG; } else - cdata += c; + { + int i; + //cdata += c; + // convert text-data on the fly if system encoding != UTF-8 + if (iconv_cd != NULL && char_size > 1 /* ((c & 0x80) == 0x80)*/) { + for (i = 0; i < char_size; i++) + convbufin[i] = ( (char)((c >> ( i << 3) ) & 0xFF) ); + convbufin[char_size] = '\0'; + bufin_size = strlen(convbufin); + bufout_size = bufin_size; + bufconverted = iconv(iconv_cd, &convbufinp, &bufin_size, &convbufoutp, &bufout_size); + + if (bufconverted != (size_t)-1 && strlen(convbufout) != 0) { + for (i = 0; i < (int)strlen(convbufout); i++) + cdata += convbufout[i]; + } else { + cdata += "?"; + } + } else { + for (i = 0; i < char_size; i++) + cdata += ( (unsigned char)((c >> ( i << 3) ) & 0xFF) ); + } + } // silently ignore until resync break; |