vdr
1.7.27
|
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 }