vdr  1.7.27
themes.c
Go to the documentation of this file.
00001 /*
00002  * themes.c: Color themes used by skins
00003  *
00004  * See the main source file 'vdr.c' for copyright information and
00005  * how to reach the author.
00006  *
00007  * $Id: themes.c 2.2 2012/02/17 13:57:32 kls Exp $
00008  */
00009 
00010 #include "themes.h"
00011 #include <dirent.h>
00012 #include <string.h>
00013 #include "config.h"
00014 #include "tools.h"
00015 
00016 // --- cTheme ----------------------------------------------------------------
00017 
00018 cTheme::cTheme(void)
00019 {
00020   name = strdup("default");
00021   memset(colorNames, 0, sizeof(colorNames));
00022   memset(colorValues, 0, sizeof(colorValues));
00023   descriptions[0] = strdup("Default");
00024 }
00025 
00026 cTheme::~cTheme()
00027 {
00028   free(name);
00029   for (int i = 0; i < MaxThemeColors; i++)
00030       free(colorNames[i]);
00031 }
00032 
00033 bool cTheme::FileNameOk(const char *FileName, bool SetName)
00034 {
00035   const char *error = NULL;
00036   if (!isempty(FileName)) {
00037      const char *d = strrchr(FileName, '/');
00038      if (d)
00039         FileName = d + 1;
00040      const char *n = strchr(FileName, '-');
00041      if (n) {
00042         if (n > FileName) {
00043            if (!strchr(++n, '-')) {
00044               const char *e = strchr(n, '.');
00045               if (e && strcmp(e, ".theme") == 0) {
00046                  if (e - n >= 1) {
00047                     // FileName is ok
00048                     if (SetName) {
00049                        free(name);
00050                        name = strndup(n, e - n);
00051                        }
00052                     }
00053                  else
00054                     error = "missing theme name";
00055                  }
00056               else
00057                  error = "invalid extension";
00058               }
00059            else
00060               error = "too many '-'";
00061            }
00062         else
00063            error = "missing skin name";
00064         }
00065      else
00066         error = "missing '-'";
00067      }
00068   else
00069      error = "empty";
00070   if (error)
00071      esyslog("ERROR: invalid theme file name (%s): '%s'", error, FileName);
00072   return !error;
00073 }
00074 
00075 const char *cTheme::Description(void)
00076 {
00077   char *s = descriptions[I18nCurrentLanguage()];
00078   if (!s)
00079      s = descriptions[0];
00080   return s ? s : name;
00081 }
00082 
00083 bool cTheme::Load(const char *FileName, bool OnlyDescriptions)
00084 {
00085   if (!FileNameOk(FileName, true))
00086      return false;
00087   bool result = false;
00088   if (!OnlyDescriptions)
00089      isyslog("loading %s", FileName);
00090   FILE *f = fopen(FileName, "r");
00091   if (f) {
00092      int line = 0;
00093      result = true;
00094      char *s;
00095      const char *error = NULL;
00096      cReadLine ReadLine;
00097      while ((s = ReadLine.Read(f)) != NULL) {
00098            line++;
00099            char *p = strchr(s, '#');
00100            if (p)
00101               *p = 0;
00102            s = stripspace(skipspace(s));
00103            if (!isempty(s)) {
00104               char *n = s;
00105               char *v = strchr(s, '=');
00106               if (v) {
00107                  *v++ = 0;
00108                  n = stripspace(skipspace(n));
00109                  v = stripspace(skipspace(v));
00110                  if (strstr(n, "Description") == n) {
00111                     int lang = 0;
00112                     char *l = strchr(n, '.');
00113                     if (l)
00114                        lang = I18nLanguageIndex(++l);
00115                     if (lang >= 0) {
00116                        free(descriptions[lang]);
00117                        descriptions[lang] = strdup(v);
00118                        }
00119                     else
00120                        error = "invalid language code";
00121                     }
00122                  else if (!OnlyDescriptions) {
00123                     for (int i = 0; i < MaxThemeColors; i++) {
00124                         if (colorNames[i]) {
00125                            if (strcmp(n, colorNames[i]) == 0) {
00126                               char *p = NULL;
00127                               errno = 0;
00128                               tColor c = strtoul(v, &p, 16);
00129                               if (!errno && !*p)
00130                                  colorValues[i] = c;
00131                               else
00132                                  error = "invalid color value";
00133                               break;
00134                               }
00135                            }
00136                         else {
00137                            error = "unknown color name";
00138                            break;
00139                            }
00140                         }
00141                     }
00142                  }
00143               else
00144                  error = "missing value";
00145               }
00146            if (error) {
00147               result = false;
00148               break;
00149               }
00150            }
00151      if (!result)
00152         esyslog("ERROR: error in %s, line %d%s%s", FileName, line, error ? ": " : "", error ? error : "");
00153      fclose(f);
00154      }
00155   else
00156      LOG_ERROR_STR(FileName);
00157   return result;
00158 }
00159 
00160 bool cTheme::Save(const char *FileName)
00161 {
00162   if (!FileNameOk(FileName))
00163      return false;
00164   bool result = true;
00165   cSafeFile f(FileName);
00166   if (f.Open()) {
00167      for (int i = 0; i < I18nLanguages()->Size(); i++) {
00168          if (descriptions[i])
00169             fprintf(f, "Description%s%.*s = %s\n", i ? "." : "", 3, i ? I18nLanguageCode(i) : "", descriptions[i]);
00170          }
00171      for (int i = 0; i < MaxThemeColors; i++) {
00172          if (colorNames[i])
00173             fprintf(f, "%s = %08X\n", colorNames[i], colorValues[i]);
00174          }
00175      if (!f.Close())
00176         result = false;
00177      }
00178   else
00179      result = false;
00180   return result;
00181 }
00182 
00183 int cTheme::AddColor(const char *Name, tColor Color)
00184 {
00185   for (int i = 0; i < MaxThemeColors; i++) {
00186       if (colorNames[i]) {
00187          if (strcmp(Name, colorNames[i]) == 0) {
00188             colorValues[i] = Color;
00189             return i;
00190             }
00191          }
00192       else {
00193          colorNames[i] = strdup(Name);
00194          colorValues[i] = Color;
00195          return i;
00196          }
00197       }
00198   return -1;
00199 }
00200 
00201 tColor cTheme::Color(int Subject)
00202 {
00203   return (Subject >= 0 && Subject < MaxThemeColors) ? colorValues[Subject] : 0;
00204 }
00205 
00206 // --- cThemes ---------------------------------------------------------------
00207 
00208 char *cThemes::themesDirectory = NULL;
00209 
00210 cThemes::cThemes(void)
00211 {
00212   numThemes = 0;
00213   names = 0;
00214   fileNames = NULL;
00215   descriptions = NULL;
00216 }
00217 
00218 cThemes::~cThemes()
00219 {
00220   Clear();
00221 }
00222 
00223 void cThemes::Clear(void)
00224 {
00225   for (int i = 0; i < numThemes; i++) {
00226       free(names[i]);
00227       free(fileNames[i]);
00228       free(descriptions[i]);
00229       }
00230   free(names);
00231   free(fileNames);
00232   free(descriptions);
00233   numThemes = 0;
00234   names = 0;
00235   fileNames = NULL;
00236   descriptions = NULL;
00237 }
00238 
00239 bool cThemes::Load(const char *SkinName)
00240 {
00241   Clear();
00242   if (themesDirectory) {
00243      cReadDir d(themesDirectory);
00244      struct dirent *e;
00245      while ((e = d.Next()) != NULL) {
00246            if (strstr(e->d_name, SkinName) == e->d_name && e->d_name[strlen(SkinName)] == '-') {
00247               cString FileName = AddDirectory(themesDirectory, e->d_name);
00248               cTheme Theme;
00249               if (Theme.Load(*FileName, true)) {
00250                  if (char **NewBuffer = (char **)realloc(names, (numThemes + 1) * sizeof(char *))) {
00251                     names = NewBuffer;
00252                     names[numThemes] = strdup(Theme.Name());
00253                     }
00254                  else {
00255                     esyslog("ERROR: out of memory");
00256                     break;
00257                     }
00258                  if (char **NewBuffer = (char **)realloc(fileNames, (numThemes + 1) * sizeof(char *))) {
00259                     fileNames = NewBuffer;
00260                     fileNames[numThemes] = strdup(*FileName);
00261                     }
00262                  else {
00263                     esyslog("ERROR: out of memory");
00264                     break;
00265                     }
00266                  if (char **NewBuffer = (char **)realloc(descriptions, (numThemes + 1) * sizeof(char *))) {
00267                     descriptions = NewBuffer;
00268                     descriptions[numThemes] = strdup(Theme.Description());
00269                     }
00270                  else {
00271                     esyslog("ERROR: out of memory");
00272                     break;
00273                     }
00274                  numThemes++;
00275                  }
00276               }
00277            }
00278      return numThemes > 0;
00279      }
00280   return false;
00281 }
00282 
00283 int cThemes::GetThemeIndex(const char *Description)
00284 {
00285   int index = 0;
00286   for (int i = 0; i < numThemes; i++) {
00287       if (strcmp(descriptions[i], Description) == 0)
00288          return i;
00289       if (strcmp(descriptions[i], "Default") == 0)
00290          index = i;
00291       }
00292   return index;
00293 }
00294 
00295 void cThemes::SetThemesDirectory(const char *ThemesDirectory)
00296 {
00297   free(themesDirectory);
00298   themesDirectory = strdup(ThemesDirectory);
00299   MakeDirs(themesDirectory, true);
00300 }
00301 
00302 void cThemes::Load(const char *SkinName, const char *ThemeName, cTheme *Theme)
00303 {
00304   cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, ThemeName);
00305   if (access(FileName, F_OK) == 0) // the file exists
00306      Theme->Load(FileName);
00307 }
00308 
00309 void cThemes::Save(const char *SkinName, cTheme *Theme)
00310 {
00311   cString FileName = cString::sprintf("%s/%s-%s.theme", themesDirectory, SkinName, Theme->Name());
00312   if (access(FileName, F_OK) != 0) // the file does not exist
00313      Theme->Save(FileName);
00314 }