summaryrefslogtreecommitdiff
path: root/xml
diff options
context:
space:
mode:
authorlordjaxom <lordjaxom>2004-12-08 18:48:39 +0000
committerlordjaxom <lordjaxom>2004-12-08 18:48:39 +0000
commit5382d18d05d358bb1c313c642395e835aa44a6a0 (patch)
tree2b5ef58620b3640c5b21e8eafe92ee4b266b1d30 /xml
parenteb2f2c9600e8f69788232582191b141002bcd522 (diff)
downloadvdr-plugin-text2skin-5382d18d05d358bb1c313c642395e835aa44a6a0.tar.gz
vdr-plugin-text2skin-5382d18d05d358bb1c313c642395e835aa44a6a0.tar.bz2
1.0-pre1v1.0-pre1
Diffstat (limited to 'xml')
-rw-r--r--xml/display.c42
-rw-r--r--xml/display.h58
-rw-r--r--xml/function.c212
-rw-r--r--xml/function.h66
-rw-r--r--xml/object.c169
-rw-r--r--xml/object.h148
-rw-r--r--xml/parser.c310
-rw-r--r--xml/parser.h14
-rw-r--r--xml/skin.c44
-rw-r--r--xml/skin.h64
-rw-r--r--xml/string.c161
-rw-r--r--xml/string.h128
-rw-r--r--xml/type.c20
-rw-r--r--xml/type.h42
-rw-r--r--xml/xml.c295
-rw-r--r--xml/xml.h63
16 files changed, 1836 insertions, 0 deletions
diff --git a/xml/display.c b/xml/display.c
new file mode 100644
index 0000000..4790b2d
--- /dev/null
+++ b/xml/display.c
@@ -0,0 +1,42 @@
+/*
+ * $Id: display.c,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#include "xml/display.h"
+
+static const std::string DisplayNames[] =
+ { "channelInfo", "channelSmall", "volume", "message", "replayInfo", "replaySmall", "menu" };
+
+cxDisplay::cxDisplay(cxSkin *parent):
+ mType((eType)__COUNT_DISPLAY__),
+ mNumWindows(0),
+ mSkin(parent)
+{
+}
+
+bool cxDisplay::ParseType(const std::string &Text)
+{
+ for (int i = 0; i < (int)__COUNT_DISPLAY__; ++i) {
+ if (DisplayNames[i].length() > 0 && DisplayNames[i] == Text) {
+ mType = (eType)i;
+ return true;
+ }
+ }
+ return false;
+}
+
+const std::string &cxDisplay::GetType(void) const
+{
+ return DisplayNames[mType];
+}
+
+cxDisplays::cxDisplays(void)
+{
+}
+
+cxDisplays::~cxDisplays()
+{
+ iterator it = begin();
+ while (it != end())
+ (delete (*it).second, ++it);
+}
diff --git a/xml/display.h b/xml/display.h
new file mode 100644
index 0000000..6c233b2
--- /dev/null
+++ b/xml/display.h
@@ -0,0 +1,58 @@
+/*
+ * $Id: display.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_DISPLAY_H
+#define VDR_TEXT2SKIN_DISPLAY_H
+
+#include "xml/object.h"
+#include <string>
+#include <map>
+
+class cxSkin;
+
+class cxDisplay {
+ friend bool xStartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool xEndElem(const std::string &name);
+
+public:
+ enum eType {
+ channelInfo,
+ channelSmall,
+ volume,
+ message,
+ replayInfo,
+ replaySmall,
+ menu,
+#define __COUNT_DISPLAY__ (menu + 1)
+ };
+
+private:
+ eType mType;
+ txWindow mWindows[MAXOSDAREAS];
+ int mNumWindows;
+ cxObjects mObjects;
+ cxSkin *mSkin;
+
+public:
+ cxDisplay(cxSkin *parent);
+
+ bool ParseType(const std::string &Text);
+ const std::string &GetType(void) const;
+
+ eType Type(void) const { return mType; }
+ const txWindow *Windows(void) const { return mWindows; }
+ int NumWindows(void) const { return mNumWindows; }
+ cxSkin *Skin(void) const { return mSkin; }
+
+ uint Objects(void) const { return mObjects.size(); }
+ const cxObject *GetObject(int n) const { return mObjects[n]; }
+};
+
+class cxDisplays: public std::map<cxDisplay::eType,cxDisplay*> {
+public:
+ cxDisplays(void);
+ ~cxDisplays();
+};
+
+#endif // VDR_TEXT2SKIN_DISPLAY_H
diff --git a/xml/function.c b/xml/function.c
new file mode 100644
index 0000000..e6e321c
--- /dev/null
+++ b/xml/function.c
@@ -0,0 +1,212 @@
+/*
+ * $Id: function.c,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $
+ */
+
+#include "xml/function.h"
+#include "render.h"
+#include "common.h"
+#include <vdr/tools.h>
+
+static const char *Internals[] = {
+ "not", "and", "or", "equal", "file", "trans", NULL
+};
+
+const std::string cxFunction::False = "";
+const std::string cxFunction::True = "1";
+
+cxFunction::cxFunction(void):
+ mType(string),
+ mString(),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cxFunction::cxFunction(const cxString &String):
+ mType(string),
+ mString(String),
+ mNumber(0),
+ mNumParams(0)
+{
+}
+
+cxFunction::cxFunction(const cxFunction &Src):
+ mType(Src.mType),
+ mString(Src.mString),
+ mNumber(Src.mNumber),
+ mNumParams(Src.mNumParams)
+{
+ for (uint i = 0; i < mNumParams; ++i)
+ mParams[i] = new cxFunction(*Src.mParams[i]);
+}
+
+cxFunction::~cxFunction()
+{
+ for (uint i = 0; i < mNumParams; ++i)
+ delete mParams[i];
+}
+
+bool cxFunction::Parse(const std::string &Text)
+{
+ const char *text = Text.c_str();
+ const char *ptr = text, *last = text;
+ eType type = undefined_function;
+ int inExpr = 0;
+ cxFunction *expr;
+
+ if (*ptr == '\'' || *ptr == '{') {
+ // must be string
+ if (strlen(ptr) < 2
+ || (*ptr == '\'' && *(ptr + strlen(ptr) - 1) != '\'')
+ || (*ptr == '{' && *(ptr + strlen(ptr) - 1) != '}')) {
+ esyslog("ERROR: Unmatched string end\n");
+ return false;
+ }
+
+ std::string temp;
+ if (*ptr == '\'')
+ temp.assign(ptr + 1, strlen(ptr) - 2);
+ else
+ temp.assign(ptr);
+
+ int pos = -1;
+ while ((pos = temp.find("\\'", pos + 1)) != -1)
+ temp.replace(pos, 1, "\'");
+
+ if (!mString.Parse(temp))
+ return false;
+
+ mType = string;
+ }
+ else {
+ // expression
+ for (; *ptr; ++ptr) {
+ if (*ptr == '(') {
+ if (inExpr++ == 0) {
+ int i;
+ for (i = 0; Internals[i] != NULL; ++i) {
+ if ((size_t)(ptr - last) == strlen(Internals[i])
+ && memcmp(last, Internals[i], ptr - last) == 0){
+ type = (eType)(INTERNAL + 1 + i);
+ break;
+ }
+ }
+
+ if (Internals[i] == NULL) {
+ esyslog("ERROR: Unknown function %.*s", (int)(ptr - last), last);
+ return false;
+ }
+ last = ptr + 1;
+ }
+ }
+ else if (*ptr == ',' || *ptr == ')') {
+ if (inExpr == 0) {
+ esyslog("ERROR: Unmatched '%c' in expression", *ptr);
+ return false;
+ }
+
+ if (inExpr == 1) {
+ expr = new cxFunction;
+ if (!expr->Parse(std::string(last, ptr - last))) {
+ delete expr;
+ return false;
+ }
+
+ mType = type;
+ mParams[mNumParams++] = expr;
+ last = ptr + 1;
+ }
+
+ if (*ptr == ')') {
+ if (inExpr == 1) {
+ int params = 0;
+
+ switch (mType) {
+ case fun_and:
+ case fun_or: params = -1; break;
+
+ case fun_eq: ++params;
+ case fun_not:
+ case fun_trans:
+ case fun_file: ++params;
+ default: break;
+ }
+
+ if (params != -1 && mNumParams != (uint)params) {
+ esyslog("ERROR: Text2Skin: Wrong number of parameters to %s, "
+ "expecting %d", Internals[mType - 1 - INTERNAL], params);
+ return false;
+ }
+ }
+
+ --inExpr;
+ }
+ }
+ }
+
+ if (inExpr > 0) {
+ esyslog("ERROR: Expecting ')' in expression");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+const std::string &cxFunction::FunFile(const std::string &Param) const
+{
+ std::string path = cText2SkinRender::ImagePath(Param);
+ Dprintf("checking file(%s)\n", path.c_str());
+ if (access(path.c_str(), F_OK) == 0)
+ return Param;
+ return False;
+}
+
+std::string cxFunction::Evaluate(void) const
+{
+ switch (mType) {
+ case string:
+ return mString.Evaluate();
+
+ case fun_not:
+ return mParams[0]->EvaluateToBool() ? False : True;
+
+ case fun_and:
+ for (uint i = 0; i < mNumParams; ++i) {
+ if (!mParams[i]->EvaluateToBool())
+ return False;
+ }
+ return True;
+
+ case fun_or:
+ for (uint i = 0; i < mNumParams; ++i) {
+ if (mParams[i]->EvaluateToBool())
+ return True;
+ }
+ return False;
+
+ case fun_eq:
+ return mParams[0]->Evaluate() == mParams[1]->Evaluate() ? True : False;
+
+ case fun_file:
+ return FunFile(mParams[0]->Evaluate());
+
+ case fun_trans:
+ return tr(mParams[0]->Evaluate().c_str());
+
+ default:
+ Dprintf("unknown function code\n");
+ esyslog("ERROR: Unknown function code called (this shouldn't happen)");
+ break;
+ }
+ return False;
+}
+
+bool cxFunction::EvaluateToBool(void)
+{
+ std::string result = Evaluate();
+ if (result == False/* || result == "0"*/)
+ return false;
+ return true;
+}
+
diff --git a/xml/function.h b/xml/function.h
new file mode 100644
index 0000000..a7d8838
--- /dev/null
+++ b/xml/function.h
@@ -0,0 +1,66 @@
+/*
+ * $Id: function.h,v 1.4 2004/12/08 18:47:37 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_XML_FUNCTION_H
+#define VDR_TEXT2SKIN_XML_FUNCTION_H
+
+#include "xml/string.h"
+#include <string>
+
+#define STRING 0x01000000
+#define NUMBER 0x02000000
+#define INTERNAL 0x04000000
+
+#define MAXPARAMETERS 16
+
+class cxFunction {
+public:
+ enum eType {
+ undefined_function,
+
+ string = STRING,
+ number = NUMBER,
+
+ fun_not = INTERNAL + 1,
+ fun_and = INTERNAL + 2,
+ fun_or = INTERNAL + 3,
+ fun_eq = INTERNAL + 4,
+ fun_file = INTERNAL + 5,
+ fun_trans = INTERNAL + 6
+ };
+
+ static const std::string False;
+ static const std::string True;
+
+private:
+ eType mType;
+ cxString mString;
+ int mNumber;
+ cxFunction *mParams[MAXPARAMETERS];
+ uint mNumParams;
+
+protected:
+ const std::string &FunFile(const std::string &Param) const;
+
+public:
+ cxFunction(void);
+ cxFunction(const cxString &String);
+ cxFunction(const cxFunction &Src);
+ ~cxFunction();
+
+ bool Parse(const std::string &Text);
+ std::string Evaluate(void) const;
+ bool EvaluateToBool(void);
+
+ void SetIndex(uint Index, int Tab);
+};
+
+inline void cxFunction::SetIndex(uint Index, int Tab)
+{
+ mString.SetIndex(Index, Tab);
+ for (uint i = 0; i < mNumParams; ++i)
+ mParams[i]->SetIndex(Index, Tab);
+}
+
+#endif // VDR_TEXT2SKIN_XML_FUNCTION_H
diff --git a/xml/object.c b/xml/object.c
new file mode 100644
index 0000000..6932106
--- /dev/null
+++ b/xml/object.c
@@ -0,0 +1,169 @@
+/*
+ * $Id: object.c,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#include "xml/object.h"
+#include "render.h"
+#include "font.h"
+
+static const std::string ObjectNames[] =
+ { "image", "text", "rectangle", "ellipse", "slope", "progress", "scrolltext", "scrollbar",
+ "block", "list", "item" };
+
+cxObject::cxObject(cxDisplay *parent):
+ mType((eType)__COUNT_OBJECT__),
+ mPos1(0, 0),
+ mPos2(-1, -1),
+ mAlpha(255),
+ mArc(0),
+ mAlign(taDefault),
+ mCondition(NULL),
+ mFont(cFont::GetFont(fontOsd)),
+ mObjects(NULL),
+ mDisplay(parent),
+ mSkin(parent->Skin())
+{
+}
+
+cxObject::cxObject(const cxObject &Src):
+ mType(Src.mType),
+ mPos1(Src.mPos1),
+ mPos2(Src.mPos2),
+ mAlpha(Src.mAlpha),
+ mArc(Src.mArc),
+ mFg(Src.mFg),
+ mBg(Src.mBg),
+ mMark(Src.mMark),
+ mActive(Src.mActive),
+ mKeep(Src.mKeep),
+ mPath(Src.mPath),
+ mText(Src.mText),
+ mAlign(Src.mAlign),
+ mCondition(NULL),
+ mCurrent(Src.mCurrent),
+ mTotal(Src.mTotal),
+ mFont(Src.mFont),
+ mObjects(NULL),
+ mDisplay(Src.mDisplay),
+ mSkin(Src.mSkin)
+{
+ if (Src.mCondition)
+ mCondition = new cxFunction(*Src.mCondition);
+ if (Src.mObjects)
+ mObjects = new cxObjects(*Src.mObjects);
+}
+
+cxObject::~cxObject()
+{
+ delete mCondition;
+ delete mObjects;
+}
+
+bool cxObject::ParseType(const std::string &Text) {
+ for (int i = 0; i < (int)__COUNT_OBJECT__; ++i) {
+ if (ObjectNames[i] == Text) {
+ mType = (eType)i;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool cxObject::ParseCondition(const std::string &Text) {
+ cxFunction *result = new cxFunction;
+ if (result->Parse(Text)) {
+ delete mCondition;
+ mCondition = result;
+ return true;
+ }
+ return false;
+}
+
+bool cxObject::ParseAlignment(const std::string &Text) {
+ if (Text == "center") mAlign = (eTextAlignment)(taTop | taCenter);
+ else if (Text == "right") mAlign = (eTextAlignment)(taTop | taRight);
+ else if (Text == "left") mAlign = (eTextAlignment)(taTop | taLeft);
+ else
+ return false;
+ return true;
+}
+
+bool cxObject::ParseFontFace(const std::string &Text) {
+ /*for (int i = 0; i < eDvbFontSize; ++i) {
+ if (FontNames[i] == Text) {
+ mFont = cFont::GetFont((eDvbFont)i);
+ return true;
+ }
+ }*/
+
+ int size = 0, pos;
+ std::string face = Text;
+ if ((pos = face.find(':')) != -1) {
+ size = atoi(face.substr(pos + 1).c_str());
+ face.erase(pos);
+ }
+ Dprintf("trying: %s %d\n", ((std::string)SkinPath() + "/fonts/" + face).c_str(), size);
+ if ((mFont = cText2SkinFont::Load(SkinPath() + "/fonts", face, size)) != NULL)
+ return true;
+ else if ((mFont = cText2SkinFont::Load(SkinPath() + "/" + mSkin->Name(), face, size)) != NULL)
+ return true;
+ return false;
+}
+
+const std::string &cxObject::TypeName(void) const {
+ return ObjectNames[mType];
+}
+
+txPoint cxObject::Pos(void) const {
+ return txPoint(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x),
+ mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y));
+}
+
+txSize cxObject::Size(void) const {
+ txPoint p1(mSkin->BaseOffset().x + (mPos1.x < 0 ? Skin()->BaseSize().w + mPos1.x : mPos1.x),
+ mSkin->BaseOffset().y + (mPos1.y < 0 ? Skin()->BaseSize().h + mPos1.y : mPos1.y));
+ txPoint p2(mSkin->BaseOffset().x + (mPos2.x < 0 ? Skin()->BaseSize().w + mPos2.x : mPos2.x),
+ mSkin->BaseOffset().y + (mPos2.y < 0 ? Skin()->BaseSize().h + mPos2.y : mPos2.y));
+ return txSize(p2.x - p1.x + 1, p2.y - p1.y + 1);
+}
+
+const tColor *cxObject::Fg(void) const
+{
+ static tColor Fg;
+ return cText2SkinRender::ItemColor(mFg, Fg) ? &Fg : NULL;
+}
+
+const tColor *cxObject::Bg(void) const
+{
+ static tColor Bg;
+ return cText2SkinRender::ItemColor(mBg, Bg) ? &Bg : NULL;
+}
+
+const tColor *cxObject::Mark(void) const
+{
+ static tColor Mark;
+ return cText2SkinRender::ItemColor(mMark, Mark) ? &Mark : NULL;
+}
+
+const tColor *cxObject::Active(void) const
+{
+ static tColor Active;
+ return cText2SkinRender::ItemColor(mActive, Active) ? &Active : NULL;
+}
+
+const tColor *cxObject::Keep(void) const
+{
+ static tColor Keep;
+ return cText2SkinRender::ItemColor(mKeep, Keep) ? &Keep : NULL;
+}
+
+cxObjects::cxObjects(void)
+{
+}
+
+cxObjects::~cxObjects()
+{
+ for (uint i = 0; i < size(); ++i)
+ delete operator[](i);
+}
+
diff --git a/xml/object.h b/xml/object.h
new file mode 100644
index 0000000..8b134a9
--- /dev/null
+++ b/xml/object.h
@@ -0,0 +1,148 @@
+/*
+ * $Id: object.h,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_XML_OBJECT_H
+#define VDR_TEXT2SKIN_XML_OBJECT_H
+
+#include "xml/string.h"
+#include "xml/function.h"
+#include <vdr/osd.h>
+#include <vector>
+#include <string>
+#include <map>
+
+class cxDisplay;
+class cxSkin;
+
+struct txPoint {
+ int x, y;
+ txPoint(int _x = 0, int _y = 0) { x = _x; y = _y; }
+};
+
+struct txSize {
+ int w, h;
+ txSize(int _w = 0, int _h = 0) { w = _w; h = _h; }
+};
+
+struct txWindow {
+ txPoint pos1;
+ txPoint pos2;
+ int bpp;
+ txWindow(int _x1 = 0, int _y1 = 0, int _x2 = -1, int _y2 = -1, int _bpp=4):
+ pos1(_x1, _y2), pos2(_x2, _y2), bpp(_bpp) {}
+};
+
+class cxObjects;
+
+class cxObject {
+ friend class cText2SkinRender;
+ friend bool xStartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool xCharData(const std::string &text);
+ friend bool xEndElem(const std::string &name);
+
+ /* Skin Editor */
+ friend class VSkinnerItem;
+
+public:
+ enum eType {
+ image,
+ text,
+ rectangle,
+ ellipse,
+ slope,
+ progress,
+ scrolltext,
+ scrollbar,
+ block,
+ list,
+ item,
+#define __COUNT_OBJECT__ (item + 1)
+ };
+
+private:
+ eType mType;
+ txPoint mPos1;
+ txPoint mPos2;
+ int mAlpha;
+ int mArc;
+ std::string mFg;
+ std::string mBg;
+ std::string mMark;
+ std::string mActive;
+ std::string mKeep;
+ cxString mPath;
+ cxString mText;
+ eTextAlignment mAlign;
+ cxFunction *mCondition;
+ cxString mCurrent;
+ cxString mTotal;
+ const cFont *mFont;
+ cxObjects *mObjects; // used for block objects such as <list>
+ cxDisplay *mDisplay;
+ cxSkin *mSkin;
+
+public:
+ cxObject(cxDisplay *parent);
+ cxObject(const cxObject &Src);
+ ~cxObject();
+
+ bool ParseType (const std::string &Text);
+ bool ParseCondition(const std::string &Text);
+ bool ParseAlignment(const std::string &Text);
+ bool ParseFontFace (const std::string &Text);
+
+ void SetIndex(uint Index, int Tab);
+
+ eType Type(void) const { return mType; }
+ cxFunction *Condition(void) const { return mCondition; }
+ int Alpha(void) const { return mAlpha; }
+ eTextAlignment Align(void) const { return mAlign; }
+ int Arc(void) const { return mArc; }
+ std::string Path(void) const { return mPath.Evaluate(); }
+ std::string Text(void) const { return mText.Evaluate(); }
+ int Current(void) const { return mCurrent.Evaluate(); }
+ int Total(void) const { return mTotal.Evaluate(); }
+ const cFont *Font(void) const { return mFont; }
+ cxDisplay *Display(void) const { return mDisplay; }
+ cxSkin *Skin(void) const { return mSkin; }
+
+ const std::string &TypeName(void) const;
+ txPoint Pos(void) const;
+ txSize Size(void) const;
+ const tColor *Fg(void) const;
+ const tColor *Bg(void) const;
+ const tColor *Mark(void) const;
+ const tColor *Active(void) const;
+ const tColor *Keep(void) const;
+
+ uint Objects(void) const;
+ const cxObject *GetObject(uint Index) const;
+};
+
+inline void cxObject::SetIndex(uint Index, int Tab)
+{
+ mText.SetIndex(Index, Tab);
+ mPath.SetIndex(Index, Tab);
+ if (mCondition != NULL)
+ mCondition->SetIndex(Index, Tab);
+}
+
+class cxObjects: public std::vector<cxObject*> {
+public:
+ cxObjects(void);
+ ~cxObjects();
+};
+
+// recursive dependancy
+inline uint cxObject::Objects(void) const
+{
+ return mObjects ? mObjects->size() : 0;
+}
+
+inline const cxObject *cxObject::GetObject(uint Index) const
+{
+ return mObjects ? (*mObjects)[Index] : NULL;
+}
+
+#endif // VDR_TEXT2SKIN_XML_OBJECT_H
diff --git a/xml/parser.c b/xml/parser.c
new file mode 100644
index 0000000..1349769
--- /dev/null
+++ b/xml/parser.c
@@ -0,0 +1,310 @@
+/*
+ * $Id: parser.c,v 1.4 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#include "xml/parser.h"
+#include "xml/xml.h"
+#include "xml/skin.h"
+#include "common.h"
+#include <vdr/tools.h>
+#include <stdio.h>
+#include <vector>
+#include <string>
+
+#define STR_SKIN "skin"
+#define STR_DISPLAY "display"
+#define STR_ID "id"
+#define STR_WINDOW "window"
+#define STR_X1 "x1"
+#define STR_Y1 "y1"
+#define STR_X "x"
+#define STR_Y "y"
+#define STR_X2 "x2"
+#define STR_Y2 "y2"
+#define STR_BPP "bpp"
+#define STR_IMAGE "image"
+#define STR_PATH "path"
+#define STR_ALPHA "alpha"
+#define STR_TEXT "text"
+#define STR_CONDITION "condition"
+#define STR_NOT "not"
+#define STR_FILE "file"
+#define STR_COLOR "color"
+#define STR_ALIGN "align"
+#define STR_RECTANGLE "rectangle"
+#define STR_ELLIPSE "ellipse"
+#define STR_SLOPE "slope"
+#define STR_PROGRESS "progress"
+#define STR_BGCOLOR "bgcolor"
+#define STR_CURRENT "current"
+#define STR_TOTAL "total"
+#define STR_VERSION "version"
+#define STR_NAME "name"
+#define STR_SCREENBASE "screenBase"
+#define STR_FONT "font"
+#define STR_ARC "arc"
+
+#define MSG_BADTAG "ERROR: The tag %s was not expected in this context"
+#define MSG_BADENDTAG "ERROR: The tag %s was not expected in this context"
+#define MSG_BADATTR "ERROR: The attribute %s was not expected in tag %s"
+#define MSG_MISSATTR "ERROR: The tag %s lacks the attribute %s"
+#define MSG_BADVALUE "ERROR: %s is not allowed for attribute %s"
+#define MSG_PARSERR "ERROR: Parser error in %s:%d: %s"
+#define MSG_BADCDATA "ERROR: Bad character data"
+#define MSG_NOFILE "ERROR: Couldn't read %s: %m"
+#define MSG_MANYWINS "ERROR: Too many windows"
+
+#define TAG_ERR_REMAIN(_context) do { \
+ esyslog("ERROR: Text2Skin: Unexpected tag %s within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define TAG_ERR_CHILD(_context) do { \
+ esyslog("ERROR: Text2Skin: No child tag %s expected within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define TAG_ERR_END(_context) do { \
+ esyslog("ERROR: Text2Skin: Unexpected closing tag for %s within %s", \
+ name.c_str(), _context); \
+ return false; \
+ } while (0)
+
+#define ATTRIB_OPT_STRING(_attr,_target) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ _target = attrs[_attr]; \
+ attrs.erase(_attr); \
+ }
+
+#define ATTRIB_MAN_STRING(_attr,_target) \
+ ATTRIB_OPT_STRING(_attr,_target) \
+ else { \
+ esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_NUMBER(_attr,_target) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ char *_e; const char *_t = attrs[_attr].c_str(); \
+ long _l = strtol(_t, &_e, 10); \
+ if (_e ==_t || *_e != '\0') { \
+ esyslog("ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \
+ _t, _attr); \
+ return false; \
+ } else \
+ _target = _l; \
+ attrs.erase(_attr); \
+ }
+
+#define ATTRIB_MAN_NUMBER(_attr,_target) \
+ ATTRIB_OPT_NUMBER(_attr,_target) \
+ else { \
+ esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+#define ATTRIB_OPT_FUNC(_attr,_func) \
+ if (attrs.find(_attr) != attrs.end()) { \
+ if (!_func(attrs[_attr])) { \
+ esyslog("ERROR: Text2Skin: Unexpected value %s for attribute %s", \
+ attrs[_attr].c_str(), _attr); \
+ return false; \
+ } \
+ attrs.erase(_attr); \
+ }
+
+#define ATTRIB_MAN_FUNC(_attr,_func) \
+ ATTRIB_OPT_FUNC(_attr,_func) \
+ else { \
+ esyslog("ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \
+ _attr, name.c_str()); \
+ return false; \
+ }
+
+static std::vector<std::string> context;
+static cxSkin *skin = NULL;
+static cxDisplay *display = NULL;
+static cxObject *parent = NULL;
+static cxObject *object = NULL;
+
+bool xStartElem(const std::string &name, std::map<std::string,std::string> &attrs) {
+ Dprintf("start element: %s\n", name.c_str());
+
+ if (context.size() == 0) {
+ if (name == "skin") {
+ ATTRIB_MAN_STRING("version", skin->mVersion);
+ ATTRIB_MAN_STRING("name", skin->mTitle);
+ ATTRIB_MAN_FUNC ("screenBase", skin->ParseBase);
+ }
+ else
+ TAG_ERR_REMAIN("document");
+ }
+ else if (context[context.size() - 1] == "skin") {
+ if (name == "display") {
+ display = new cxDisplay(skin);
+ ATTRIB_MAN_FUNC ("id", display->ParseType);
+ }
+ else
+ TAG_ERR_REMAIN("skin");
+ }
+ else if (context[context.size() - 1] == "display"
+ || context[context.size() - 1] == "list"
+ || context[context.size() - 1] == "block") {
+ if (object != NULL) {
+ parent = object;
+ object = NULL;
+ }
+
+ if (name == "window") {
+ if (display->mNumWindows < MAXOSDAREAS) {
+ txWindow window;
+ ATTRIB_OPT_NUMBER("x1", window.pos1.x);
+ ATTRIB_OPT_NUMBER("y1", window.pos1.y);
+ ATTRIB_OPT_NUMBER("x2", window.pos2.x);
+ ATTRIB_OPT_NUMBER("y2", window.pos2.y);
+ ATTRIB_OPT_NUMBER("bpp", window.bpp);
+ display->mWindows[display->mNumWindows++] = window;
+ } else
+ esyslog("ERROR: Text2Skin: Too many windows in display");
+ }
+ else {
+ object = new cxObject(display);
+ if (object->ParseType(name)) {
+ ATTRIB_OPT_NUMBER("x1", object->mPos1.x);
+ ATTRIB_OPT_NUMBER("y1", object->mPos1.y);
+ ATTRIB_OPT_NUMBER("x2", object->mPos2.x);
+ ATTRIB_OPT_NUMBER("y2", object->mPos2.y);
+ ATTRIB_OPT_FUNC ("condition", object->ParseCondition);
+
+ if (name == "image") {
+ ATTRIB_OPT_NUMBER("x", object->mPos1.x);
+ ATTRIB_OPT_NUMBER("y", object->mPos1.y);
+ ATTRIB_OPT_NUMBER("alpha", object->mAlpha);
+ ATTRIB_OPT_STRING("color", object->mFg);
+ ATTRIB_OPT_STRING("bgColor", object->mBg);
+ ATTRIB_MAN_FUNC ("path", object->mPath.Parse);
+ }
+ else if (name == "text"
+ || name == "scrolltext") {
+ ATTRIB_OPT_STRING("color", object->mFg);
+ ATTRIB_OPT_FUNC ("align", object->ParseAlignment);
+ ATTRIB_OPT_FUNC ("font", object->ParseFontFace);
+ }
+ else if (name == "rectangle") {
+ ATTRIB_OPT_STRING("color", object->mFg);
+ }
+ else if (name == "ellipse" || name == "slope") {
+ ATTRIB_OPT_STRING("color", object->mFg);
+ ATTRIB_OPT_NUMBER("arc", object->mArc);
+ }
+ else if (name == "progress"
+ || name == "scrollbar") {
+ ATTRIB_OPT_STRING("color", object->mFg);
+ ATTRIB_OPT_STRING("bgColor", object->mBg);
+ ATTRIB_OPT_FUNC ("current", object->mCurrent.Parse);
+ ATTRIB_OPT_FUNC ("total", object->mTotal.Parse);
+ }
+ else if (name == "item") {
+ ATTRIB_MAN_NUMBER("height", object->mPos2.y);
+ --object->mPos2.y;
+ }
+ } else
+ TAG_ERR_REMAIN(context[context.size() - 1].c_str());
+ }
+ } else
+ TAG_ERR_CHILD(context[context.size() - 1].c_str());
+ context.push_back(name);
+ return true;
+}
+
+bool xCharData(const std::string &text) {
+ int start = 0, end = text.length() - 1;
+
+ Dprintf("char data before: %s\n", text.c_str());
+
+ while (text[start] == '\012' || text[start] == '\015' || text[start] == ' ' || text[start] == '\t')
+ ++start;
+
+ while (text[end] == '\012' || text[end] == '\015' || text[end] == ' ' || text[end] == '\t')
+ --end;
+
+ Dprintf("char data after: %s\n", text.substr(start, end - start + 1).c_str());
+
+ if (end - start + 1 > 0) {
+ Dprintf("context: %s\n", context[context.size() - 1].c_str());
+ if (context[context.size() - 1] == "text"
+ || context[context.size() - 1] == "scrolltext") {
+ if (!object->mText.Parse(text.substr(start, end - start + 1)))
+ return false;
+ } else
+ esyslog(MSG_BADCDATA);
+ }
+ return true;
+}
+
+bool xEndElem(const std::string &name) {
+ Dprintf("end element: %s\n", name.c_str());
+ if (context[context.size() - 1] == name) {
+ if (name == "display") {
+ skin->mDisplays[display->Type()] = display;
+ display = NULL;
+ }
+ else if (object != NULL || parent != NULL) {
+ if (object == NULL) {
+ Dprintf("rotating parent to object\n");
+ object = parent;
+ parent = NULL;
+ }
+
+ if (object->mCondition == NULL) {
+ switch (object->mType) {
+ case cxObject::text:
+ object->mCondition = new cxFunction(object->mText);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (parent != NULL) {
+ Dprintf("pushing to parent\n");
+ if (parent->mObjects == NULL)
+ parent->mObjects = new cxObjects();
+ parent->mObjects->push_back(object);
+ }
+ else
+ display->mObjects.push_back(object);
+ object = NULL;
+ }
+ context.pop_back();
+ } else
+ TAG_ERR_END(context[context.size() - 1].c_str());
+ return true;
+}
+
+cxSkin *xmlParse(const std::string &name, const std::string &fileName) {
+ skin = new cxSkin(name);
+ context.clear();
+
+ XML xml(fileName);
+ xml.nodeStartCB(xStartElem);
+ xml.nodeEndCB(xEndElem);
+ xml.cdataCB(xCharData);
+ if (xml.parse() != 0) {
+ esyslog("ERROR: Text2Skin: Parse error in %s, line %d", fileName.c_str(), xml.lineNr());
+ DELETENULL(skin);
+ DELETENULL(display);
+ DELETENULL(object);
+ return NULL;
+ }
+
+ cxSkin *result = skin;
+ skin = NULL;
+ return result;
+}
+
diff --git a/xml/parser.h b/xml/parser.h
new file mode 100644
index 0000000..60fe30c
--- /dev/null
+++ b/xml/parser.h
@@ -0,0 +1,14 @@
+/*
+ * $Id: parser.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_PARSER_H
+#define VDR_TEXT2SKIN_PARSER_H
+
+#include <string>
+
+class cxSkin;
+
+cxSkin *xmlParse(const std::string &name, const std::string &fileName);
+
+#endif // VDR_TEXT2SKIN_PARSER_H
diff --git a/xml/skin.c b/xml/skin.c
new file mode 100644
index 0000000..0cc753b
--- /dev/null
+++ b/xml/skin.c
@@ -0,0 +1,44 @@
+/*
+ * $Id: skin.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#include "xml/skin.h"
+#include <vdr/tools.h>
+#include <vdr/config.h>
+
+const std::string ScreenBases[] = { "relative", "absolute" };
+
+cxSkin::cxSkin(const std::string &Name):
+ mName(Name) {
+}
+
+void cxSkin::SetBase(eScreenBase Base) {
+ mBase = Base;
+ switch (mBase) {
+ case relative:
+ mBaseOffset = txPoint(Setup.OSDLeft, Setup.OSDTop);
+ mBaseSize = txSize(Setup.OSDWidth, Setup.OSDHeight);
+ break;
+
+ case absolute:
+ mBaseOffset = txPoint(0, 0);
+ mBaseSize = txSize(720, 576); //XXX
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool cxSkin::ParseBase(const std::string &Text) {
+ int i;
+ for (i = 0; i < (int)__COUNT_BASE__; ++i) {
+ if (ScreenBases[i] == Text)
+ break;
+ }
+ if (i < (int)__COUNT_BASE__) {
+ SetBase((eScreenBase)i);
+ return true;
+ }
+ return false;
+}
diff --git a/xml/skin.h b/xml/skin.h
new file mode 100644
index 0000000..40e25e7
--- /dev/null
+++ b/xml/skin.h
@@ -0,0 +1,64 @@
+/*
+ * $Id: skin.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_XML_SKIN_H
+#define VDR_TEXT2SKIN_XML_SKIN_H
+
+#include "xml/display.h"
+#include <vdr/osd.h>
+#include <expat.h>
+#include <map>
+#include <string>
+
+// --- cxSkin -----------------------------------------------------------------
+
+class cxSkin {
+ friend bool xStartElem(const std::string &name, std::map<std::string,std::string> &attrs);
+ friend bool xEndElem(const std::string &name);
+
+ /* Skin Editor */
+ friend class VSkinnerView;
+
+public:
+ enum eScreenBase {
+ relative,
+ absolute,
+#define __COUNT_BASE__ (absolute + 1)
+ };
+
+private:
+ eScreenBase mBase;
+ txPoint mBaseOffset;
+ txSize mBaseSize;
+ std::string mName;
+ std::string mTitle;
+ std::string mVersion;
+
+ cxDisplays mDisplays;
+
+protected:
+ void SetBase(eScreenBase Base);
+
+public:
+ cxSkin(const std::string &Name);
+
+ cxDisplay *Get(cxDisplay::eType Type);
+
+ bool ParseBase(const std::string &Text);
+
+ eScreenBase Base(void) const { return mBase; }
+ const txPoint &BaseOffset(void) const { return mBaseOffset; }
+ const txSize &BaseSize(void) const { return mBaseSize; }
+ const std::string &Name(void) const { return mName; }
+ const std::string &Title(void) const { return mTitle; }
+ const std::string &Version(void) const { return mVersion; }
+};
+
+inline cxDisplay *cxSkin::Get(cxDisplay::eType Type) {
+ if (mDisplays.find(Type) != mDisplays.end())
+ return mDisplays[Type];
+ return NULL;
+}
+
+#endif // VDR_TEXT2SKIN_XML_SKIN_H
diff --git a/xml/string.c b/xml/string.c
new file mode 100644
index 0000000..051a003
--- /dev/null
+++ b/xml/string.c
@@ -0,0 +1,161 @@
+/*
+ * $Id: string.c,v 1.5 2004/12/08 17:22:28 lordjaxom Exp $
+ */
+
+#include "xml/string.h"
+#include "render.h"
+#include <vdr/tools.h>
+
+static const char *Tokens[__COUNT_TOKEN__] = {
+ "DateTime",
+
+ // Channel Display
+ "ChannelNumber", "ChannelName", "ChannelShortName", "ChannelBouquet", "PresentStartDateTime",
+ "PresentVPSDateTime", "PresentEndDateTime", "PresentDuration", "PresentProgress",
+ "PresentTitle", "PresentShortText", "PresentDescription", "FollowingStartDateTime",
+ "FollowingVPSDateTime", "FollowingEndDateTime", "FollowingDuration",
+ "FollowingTitle", "FollowingShortText", "FollowingDescription", "Language",
+ "HasTeletext", "HasMultilang", "HasDolby", "IsEncrypted", "IsRadio", "IsRecording", "HasVPS",
+ "HasTimer", "IsRunning",
+
+ // Volume Display
+ "VolumeCurrent", "VolumeTotal", "IsMute",
+
+ // Message Display
+ "Message", "MessageStatus", "MessageInfo", "MessageWarning",
+ "MessageError",
+
+ // Replay Display
+ "ReplayTitle", "ReplayPositionIndex", "ReplayDurationIndex", "ReplayPrompt", "IsPlaying",
+ "IsFastForward", "IsFastRewind", "IsSlowForward", "IsSlowRewind", "IsPausing",
+ "ReplayPosition", "ReplayDuration", "ReplayMode",
+
+ // Menu Page
+ "MenuTitle", "MenuGroup", "IsMenuGroup", "MenuItem", "IsMenuItem", "MenuCurrent", "IsMenuCurrent",
+ "MenuText", "ButtonRed", "ButtonGreen", "ButtonYellow", "ButtonBlue", "CanScrollUp",
+ "CanScrollDown"
+};
+
+std::string txToken::Token(const txToken &Token) {
+ std::string result = (std::string)"{" + Tokens[Token.Type];
+ if (Token.Attrib.length() > 0)
+ result += ":" + Token.Attrib;
+ result += "}";
+
+ return result;
+}
+
+cxString::cxString(void) {
+}
+
+bool cxString::Parse(const std::string &Text) {
+ const char *text = Text.c_str();
+ const char *ptr = text, *last = text;
+ bool inToken = false;
+ bool inAttrib = false;
+ int offset = 0;
+
+ Dprintf("parsing: %s\n", Text.c_str());
+
+ for (; *ptr; ++ptr) {
+ if (inToken && *ptr == '\\') {
+ if (*(ptr + 1) == '\0') {
+ esyslog("ERROR: Stray \\ in token attribute\n");
+ return false;
+ }
+
+ ++ptr;
+ continue;
+ }
+ else if (*ptr == '{') {
+ if (inToken) {
+ esyslog("ERROR: Unexpected '{' in token");
+ return false;
+ }
+
+ mText.append(last, ptr - last);
+ last = ptr + 1;
+ inToken = true;
+ }
+ else if (*ptr == '}' || (inToken && *ptr == ':')) {
+ if (!inToken) {
+ esyslog("ERROR: Unexpected '}' outside of token");
+ return false;
+ }
+
+ if (inAttrib) {
+ if (*ptr == ':') {
+ esyslog("ERROR: Unexpected ':' inside of token attribute");
+ return false;
+ }
+
+ int pos = -1;
+ txToken &lastToken = mTokens[mTokens.size() - 1];
+ lastToken.Attrib.assign(last, ptr - last);
+ while ((pos = lastToken.Attrib.find('\\', pos + 1)) != -1) {
+ switch (lastToken.Attrib[pos + 1]) {
+ case 'n':
+ lastToken.Attrib.replace(pos, 2, "\n");
+ break;
+
+ default:
+ lastToken.Attrib.erase(pos, 1);
+ }
+ }
+
+ inAttrib = false;
+ inToken = false;
+ } else {
+ int i;
+ for (i = 0; i < (int)__COUNT_TOKEN__; ++i) {
+ if ((size_t)(ptr - last) == strlen(Tokens[i])
+ && memcmp(last, Tokens[i], ptr - last) == 0) {
+ txToken token((exToken)i, offset, "");
+ mTokens.push_back(token);
+ break;
+ }
+ }
+
+ if (i == (int)__COUNT_TOKEN__) {
+ esyslog("ERROR: Unexpected token {%.*s}", (int)(ptr - last), last);
+ return false;
+ }
+
+ if (*ptr == ':')
+ inAttrib = true;
+ else
+ inToken = false;
+ }
+
+ last = ptr + 1;
+ }
+ else if (!inToken)
+ ++offset;
+ }
+
+ if (inToken) {
+ esyslog("ERROR: Expecting '}' in token");
+ return false;
+ }
+
+ mText.append(last, ptr - last);
+ return true;
+}
+
+cxType cxString::Evaluate(void) const
+{
+ std::string result;
+ int offset = 0;
+
+ if (mText.length() == 0 && mTokens.size() == 1)
+ return cText2SkinRender::GetToken(mTokens[0]);
+
+ for (uint i = 0; i < mTokens.size(); ++i) {
+ result.append(mText.c_str() + offset, mTokens[i].Offset - offset);
+ result.append(cText2SkinRender::GetToken(mTokens[i]));
+ offset = mTokens[i].Offset;
+ }
+ result.append(mText.c_str() + offset);
+ return result;
+}
+
diff --git a/xml/string.h b/xml/string.h
new file mode 100644
index 0000000..5c89d13
--- /dev/null
+++ b/xml/string.h
@@ -0,0 +1,128 @@
+/*
+ * $Id: string.h,v 1.5 2004/12/08 18:47:37 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_XML_STRING_H
+#define VDR_TEXT2SKIN_XML_STRING_H
+
+#include "xml/type.h"
+#include <string>
+#include <vector>
+
+enum exToken {
+ tDateTime,
+
+ // Channel Display
+ tChannelNumber,
+ tChannelName,
+ tChannelShortName,
+ tChannelBouquet,
+ // next 8 also in Menu
+ tPresentStartDateTime,
+ tPresentVPSDateTime,
+ tPresentEndDateTime,
+ tPresentDuration,
+ tPresentProgress,
+ tPresentTitle,
+ tPresentShortText,
+ tPresentDescription,
+ tFollowingStartDateTime,
+ tFollowingVPSDateTime,
+ tFollowingEndDateTime,
+ tFollowingDuration,
+ tFollowingTitle,
+ tFollowingShortText,
+ tFollowingDescription,
+ tLanguage,
+ tHasTeletext,
+ tHasMultilang,
+ tHasDolby,
+ tIsEncrypted,
+ tIsRadio,
+ tIsRecording,
+ // next 3 also in Menu
+ tHasVPS,
+ tHasTimer,
+ tIsRunning,
+
+ // VolumeDisplay
+ tVolumeCurrent,
+ tVolumeTotal,
+ tIsMute,
+
+ // Message Display
+ tMessage,
+ tMessageStatus,
+ tMessageInfo,
+ tMessageWarning,
+ tMessageError,
+
+ // Replay Display
+ tReplayTitle,
+ tReplayPositionIndex,
+ tReplayDurationIndex,
+ tReplayPrompt,
+ tIsPlaying,
+ tIsFastForward,
+ tIsFastRewind,
+ tIsSlowForward,
+ tIsSlowRewind,
+ tIsPausing,
+ tReplayPosition,
+ tReplayDuration,
+ tReplayMode,
+
+ // Menu Page
+ tMenuTitle,
+ tMenuGroup,
+ tIsMenuGroup,
+ tMenuItem,
+ tIsMenuItem,
+ tMenuCurrent,
+ tIsMenuCurrent,
+ tMenuText,
+ tButtonRed,
+ tButtonGreen,
+ tButtonYellow,
+ tButtonBlue,
+ tCanScrollUp,
+ tCanScrollDown,
+
+#define __COUNT_TOKEN__ (tCanScrollDown + 1)
+};
+
+struct txToken {
+ exToken Type;
+ uint Offset;
+ std::string Attrib;
+ int Index;
+ int Tab;
+
+ txToken(void): Index(-1), Tab(-1) {}
+ txToken(exToken t, uint o, const std::string &a): Type(t), Offset(o), Attrib(a), Index(-1), Tab(-1) {}
+ static std::string Token(const txToken &Token);
+};
+
+class cxString {
+private:
+ std::string mText;
+ std::vector<txToken> mTokens;
+
+public:
+ cxString(void);
+
+ bool Parse(const std::string &Text);
+ cxType Evaluate(void) const;
+
+ void SetIndex(uint Index, int Tab);
+};
+
+inline void cxString::SetIndex(uint Index, int Tab)
+{
+ for (uint i = 0; i < mTokens.size(); ++i) {
+ mTokens[i].Index = Index;
+ mTokens[i].Tab = Tab;
+ }
+}
+
+#endif // VDR_TEXT2SKIN_XML_STRING_H
diff --git a/xml/type.c b/xml/type.c
new file mode 100644
index 0000000..d311b30
--- /dev/null
+++ b/xml/type.c
@@ -0,0 +1,20 @@
+/*
+ * $Id: type.c,v 1.2 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#include "xml/type.h"
+#include "xml/function.h"
+#include <stdio.h>
+
+const std::string &cxType::String(void) {
+ static char buffer[50];
+ if (mType == number) {
+ snprintf(buffer, sizeof(buffer), "%d", mNumber);
+ mString = buffer;
+ mType = string;
+ } else if (mType == boolean) {
+ mString = mNumber ? cxFunction::True : cxFunction::False;
+ mType = string;
+ }
+ return mString;
+}
diff --git a/xml/type.h b/xml/type.h
new file mode 100644
index 0000000..1b1113c
--- /dev/null
+++ b/xml/type.h
@@ -0,0 +1,42 @@
+/*
+ * $Id: type.h,v 1.3 2004/12/08 17:13:26 lordjaxom Exp $
+ */
+
+#ifndef VDR_TEXT2SKIN_XML_TYPE_H
+#define VDR_TEXT2SKIN_XML_TYPE_H
+
+#include <string>
+
+class cxType {
+public:
+ enum eType {
+ string,
+ number,
+ boolean
+ };
+
+private:
+ eType mType;
+ std::string mString;
+ int mNumber;
+
+public:
+ cxType(const char *String): mType(string), mString(String ?: "") {}
+ cxType(std::string String): mType(string), mString(String) {}
+ cxType(int Number): mType(number), mNumber(Number) {}
+ cxType(time_t Number): mType(number), mNumber(Number) {}
+ cxType(bool Value): mType(boolean), mNumber(Value ? 1 : 0) {}
+
+ const std::string &String(void);
+ int Number(void) const;
+
+ operator std::string () { return String(); }
+ operator int () { return Number(); }
+ operator bool () { return Number(); }
+};
+
+inline int cxType::Number(void) const {
+ return mType == number ? mNumber : 0;
+}
+
+#endif // VDR_TEXT2SKIN_XML_TYPE_H
diff --git a/xml/xml.c b/xml/xml.c
new file mode 100644
index 0000000..07dae8c
--- /dev/null
+++ b/xml/xml.c
@@ -0,0 +1,295 @@
+/*
+ * $Id: xml.c,v 1.2 2004/12/06 15:01:02 lordjaxom Exp $
+ * This module was kindly provided by Clemens Kirchgatterer
+ */
+
+#include <ctype.h>
+
+#include <iostream>
+#include <fstream>
+
+#include "xml.h"
+
+using namespace std;
+
+enum {
+ LOOK4START, // looking for first element start
+ LOOK4TAG, // looking for element tag
+ INTAG, // reading tag
+ LOOK4ATTRN, // looking for attr name, > or /
+ INATTRN, // reading attr name
+ LOOK4ATTRV, // looking for attr value
+ SAWSLASH, // saw / in element opening
+ INATTRV, // in attr value
+ LOOK4CLOSETAG, // looking for closing tag after <
+ INCLOSETAG, // reading closing tag
+};
+
+XML::XML(const string &file) {
+ char *buffer;
+ long size;
+
+ ifstream f(file.c_str(), ios::in|ios::binary|ios::ate);
+ size = f.tellg();
+ f.seekg(0, ios::beg);
+ buffer = new char [size];
+ f.read(buffer, size);
+ f.close();
+ data = buffer;
+ delete[] buffer;
+ nodestartcb = NULL;
+ nodeendcb = NULL;
+ cdatacb = NULL;
+ parseerrorcb = NULL;
+ progresscb = NULL;
+}
+
+XML::XML(const char *mem, unsigned int len) {
+ data.assign(mem, len);
+ nodestartcb = NULL;
+ nodeendcb = NULL;
+ cdatacb = NULL;
+ parseerrorcb = NULL;
+ progresscb = NULL;
+}
+
+void
+XML::nodeStartCB(XML_NODE_START_CB(cb)) {
+ nodestartcb = cb;
+}
+
+void
+XML::nodeEndCB(XML_NODE_END_CB(cb)) {
+ nodeendcb = cb;
+}
+
+void
+XML::cdataCB(XML_CDATA_CB(cb)) {
+ cdatacb = cb;
+}
+
+void
+XML::parseErrorCB(XML_PARSE_ERROR_CB(cb)) {
+ parseerrorcb = cb;
+}
+
+void
+XML::progressCB(XML_PROGRESS_CB(cb)) {
+ progresscb = cb;
+}
+
+int
+XML::parse(void) {
+ float percent = 0;
+ unsigned int len;
+ int last = 0;
+
+ state = LOOK4START;
+ linenr = 1;
+ skipping = false;
+ len = data.length();
+ for (unsigned int i=0; i<len; i++) {
+ if (readChar(data[i])) return (-1);
+ if (progresscb) {
+ percent = ((float)i/len)*100;
+ if ((int)percent>last) {
+ progresscb((int)percent);
+ last = ((int)percent);
+ }
+ }
+ }
+ return (0);
+}
+
+bool
+XML::isTokenChar(bool start, int c) {
+ return (isalpha(c) || c == '_' || (!start && isdigit(c)));
+}
+
+int
+XML::readChar(int c) {
+ // new line?
+ if (c == '\n') linenr++;
+
+ switch (state) {
+
+ // looking for element start
+ case LOOK4START:
+ if (c == '<') {
+ if (cdatacb) {
+ int pos = 0;
+ while ((pos = cdata.find('&', pos)) != -1) {
+ if (cdata.substr(pos, 4) == "&lt;")
+ cdata.replace(pos, 4, "<");
+ else if (cdata.substr(pos, 4) == "&gt;")
+ cdata.replace(pos, 4, ">");
+ else if (cdata.substr(pos, 5) == "&amp;")
+ cdata.replace(pos, 5, "&");
+ ++pos;
+ }
+ if (!cdatacb(cdata))
+ return (-1);
+ }
+ cdata = "";
+ attr.clear();
+ tag = "";
+ state = LOOK4TAG;
+ } else
+ cdata += c;
+ // silently ignore until resync
+ break;
+
+ // looking for element tag
+ case LOOK4TAG:
+ // skip comments and declarations.
+ if (skipping) {
+ if (c == '>') {
+ skipping = false;
+ state = LOOK4START;
+ }
+ break;
+ } else {
+ if (c == '?' || c == '!') {
+ skipping = true;
+ break;
+ }
+ }
+ if (isTokenChar(1, c)) {
+ tag += c;
+ state = INTAG;
+ } else if (c == '/') {
+ state = LOOK4CLOSETAG;
+ } else if (!isspace(c)) {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus tag char", c);
+ }
+ return (-1);
+ }
+ break;
+
+ // reading tag
+ case INTAG:
+ if (isTokenChar(0, c)) {
+ tag += c;
+ } else if (c == '>') {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return (-1);
+ state = LOOK4START;
+ } else if (c == '/') {
+ state = SAWSLASH;
+ } else {
+ state = LOOK4ATTRN;
+ }
+ break;
+
+ // looking for attr name, > or /
+ case LOOK4ATTRN:
+ if (c == '>') {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return (-1);
+ state = LOOK4START;
+ } else if (c == '/') {
+ state = SAWSLASH;
+ } else if (isTokenChar(1, c)) {
+ attrn = "";
+ attrn += c;
+ state = INATTRN;
+ } else if (!isspace(c)) {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus 1st attr name char", c);
+ }
+ return (-2);
+ }
+ break;
+
+ // saw / in element opening
+ case SAWSLASH:
+ if (c == '>') {
+ if (nodestartcb)
+ if (!nodestartcb(tag, attr))
+ return (-1);
+ if (nodeendcb)
+ if (!nodeendcb(tag))
+ return (-1);
+ state = LOOK4START;
+ } else {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus char before >", c);
+ }
+ return (-3);
+ }
+ break;
+
+ // reading attr name
+ case INATTRN:
+ if (isTokenChar(0, c)) {
+ attrn += c;
+ } else if (isspace(c) || c == '=') {
+ state = LOOK4ATTRV;
+ } else {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus attr name char", c);
+ }
+ return (-4);
+ }
+ break;
+
+ // looking for attr value
+ case LOOK4ATTRV:
+ if (c == '\'' || c == '"') {
+ delim = c;
+ attrv = "";
+ state = INATTRV;
+ } else if (!(isspace(c) || c == '=')) {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "No attribute value", c);
+ }
+ return (-5);
+ }
+ break;
+
+ // in attr value
+ case INATTRV:
+ if (c == delim) {
+ attr[attrn] = attrv;
+ state = LOOK4ATTRN;
+ } else if (!iscntrl(c)) {
+ attrv += c;
+ }
+ break;
+
+ // looking for closing tag after <
+ case LOOK4CLOSETAG:
+ if (isTokenChar(1, c)) {
+ tag += c;
+ state = INCLOSETAG;
+ } else if (!isspace(c)) {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus preend tag char", c);
+ }
+ return (-6);
+ }
+ break;
+
+ // reading closing tag
+ case INCLOSETAG:
+ if (isTokenChar(0, c)) {
+ tag += c;
+ } else if (c == '>') {
+ if (nodeendcb)
+ if (!nodeendcb(tag))
+ return false;
+ state = LOOK4START;
+ } else if (!isspace(c)) {
+ if (parseerrorcb) {
+ parseerrorcb(linenr, "Bogus end tag char", c);
+ }
+ return (-7);
+ }
+ break;
+ }
+
+ return (0);
+}
diff --git a/xml/xml.h b/xml/xml.h
new file mode 100644
index 0000000..9abc641
--- /dev/null
+++ b/xml/xml.h
@@ -0,0 +1,63 @@
+/*
+ * $Id: xml.h,v 1.1.1.1 2004/11/19 16:45:31 lordjaxom Exp $
+ * This module was kindly provided by Clemens Kirchgatterer
+ */
+
+#ifndef _XML_H_
+#define _XML_H_
+
+#include <string>
+#include <map>
+
+#define XML_NODE_START_CB(CB) \
+bool (*CB)(const std::string &tag, std::map<std::string, std::string> &attr)
+#define XML_NODE_END_CB(CB) \
+bool (*CB)(const std::string &tag)
+#define XML_CDATA_CB(CB) \
+bool (*CB)(const std::string &text)
+#define XML_PARSE_ERROR_CB(CB) \
+void (*CB)(int line, const char *txt, char c)
+#define XML_PROGRESS_CB(CB) \
+void (*CB)(int percent)
+
+class XML {
+
+public:
+
+ XML(const std::string &file);
+ XML(const char *mem, unsigned int len);
+
+ void nodeStartCB(XML_NODE_START_CB(cb));
+ void nodeEndCB(XML_NODE_END_CB(cb));
+ void cdataCB(XML_CDATA_CB(cb));
+ void parseErrorCB(XML_PARSE_ERROR_CB(cb));
+ void progressCB(XML_PROGRESS_CB(cb));
+
+ int parse(void);
+
+ int lineNr(void) const { return linenr; }
+
+protected:
+
+ bool isTokenChar(bool start, int c);
+ int readChar(int c);
+
+private:
+
+ bool skipping;
+ int state;
+ int linenr;
+ int delim;
+
+ std::string data, cdata, tag, attrn, attrv;
+ std::map<std::string, std::string> attr;
+
+ XML_NODE_START_CB(nodestartcb);
+ XML_NODE_END_CB(nodeendcb);
+ XML_CDATA_CB(cdatacb);
+ XML_PARSE_ERROR_CB(parseerrorcb);
+ XML_PROGRESS_CB(progresscb);
+
+};
+
+#endif // _XML_H_