source: trunk/module-webif-tpl.c@ 8438

Last change on this file since 8438 was 8438, checked in by gf, 9 years ago

Revert "webif: Remove the need to save config info in struct templates."

This reverts commit r8435. There is a use case in which external
templates declare other dependencies than the built-in ones.

This also fixes a problem with picons loading.

File size: 20.7 KB
Line 
1#include "globals.h"
2
3#ifdef WEBIF
4#include "webif/pages.h"
5#include "module-webif-tpl.h"
6#include "oscam-files.h"
7#include "oscam-string.h"
8
9extern uint8_t cs_http_use_utf8;
10
11/* struct template templates[] that comes from webif/pages.c is recreated as
12 struct tpl tpls[] because we need to add additional fields such as tpl_name_hash
13 and possibly preprocess templates[] struct before using it. */
14
15struct tpl {
16 uint32_t tpl_name_hash;
17 const char *tpl_name;
18 const char *tpl_data;
19 const char *tpl_deps;
20 uint32_t tpl_data_len;
21};
22
23static struct tpl *tpls;
24static int tpls_count;
25
26void webif_tpls_prepare(void) {
27 int i;
28 extern const struct template templates[];
29 tpls_count = templates_count();
30 if (!cs_malloc(&tpls, tpls_count * sizeof(struct tpl))) {
31 tpls_count = 0;
32 return;
33 }
34 for(i = 0; i < tpls_count; ++i) {
35 tpls[i].tpl_name_hash = jhash(templates[i].tpl_name, strlen(templates[i].tpl_name));
36 tpls[i].tpl_name = templates[i].tpl_name;
37 tpls[i].tpl_data = templates[i].tpl_data;
38 tpls[i].tpl_deps = templates[i].tpl_deps;
39 tpls[i].tpl_data_len = templates[i].tpl_data_len;
40 }
41}
42
43void webif_tpls_free(void) {
44 free(tpls);
45}
46
47/* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
48 use (but you should not call free/realloc on this!)*/
49char *tpl_addVar(struct templatevars *vars, uint8_t addmode, char *name, char *value){
50 if (name == NULL) return "";
51 if (value == NULL) value = "";
52 int32_t i;
53 char *tmp = NULL, *result = NULL;
54 for(i = (*vars).varscnt-1; i >= 0; --i) {
55 if (strcmp((*vars).names[i], name) == 0) {
56 result = (*vars).values[i];
57 break;
58 }
59 }
60 if (result == NULL) {
61 if ((*vars).varsalloc <= (*vars).varscnt) {
62 if (!cs_realloc(&(*vars).names, (*vars).varsalloc * 2 * sizeof(char**))) return "";
63 if (!cs_realloc(&(*vars).values, (*vars).varsalloc * 2 * sizeof(char**))) return "";
64 if (!cs_realloc(&(*vars).vartypes, (*vars).varsalloc * 2 * sizeof(uint8_t*))) return "";
65 (*vars).varsalloc = (*vars).varscnt * 2;
66 }
67 int32_t len = strlen(name) + 1;
68 if (!cs_malloc(&tmp, len)) return "";
69 memcpy(tmp, name, len);
70 (*vars).names[(*vars).varscnt] = tmp;
71 len = strlen(value) + 1;
72 if (!cs_malloc(&tmp, len)) {
73 free((*vars).names[(*vars).varscnt]);
74 return "";
75 }
76 memcpy(tmp, value, len);
77 (*vars).values[(*vars).varscnt] = tmp;
78 (*vars).vartypes[(*vars).varscnt] = addmode;
79 (*vars).varscnt++;
80 } else {
81 int32_t oldlen = 0, newlen = strlen(value);
82 if (addmode == TPLAPPEND || addmode == TPLAPPENDONCE) oldlen = strlen((*vars).values[i]);
83 if (!cs_realloc(&((*vars).values[i]), oldlen + newlen + 1)) return value;
84 memcpy((*vars).values[i] + oldlen, value, newlen + 1);
85 (*vars).vartypes[i] = addmode;
86 }
87 return tmp;
88}
89
90/* Adds a message to be output on the page using the TPLMESSAGE template. */
91char *tpl_addMsg(struct templatevars *vars, char *value) {
92 tpl_addVar(vars, TPLADDONCE, "MESSAGE", value);
93 (*vars).messages++;
94 return tpl_addVar(vars, TPLAPPEND, "MESSAGES", tpl_getTpl(vars, "MESSAGEBIT"));
95}
96
97/* Allows to add a char array which has been allocated by malloc. It will automatically get
98 freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
99 it after having added the array here! */
100char *tpl_addTmp(struct templatevars *vars, char *value) {
101 if (value == NULL) return "";
102 if ((*vars).tmpalloc <= (*vars).tmpcnt) {
103 if (!cs_realloc(&(*vars).tmp, (*vars).tmpalloc * 2 * sizeof(char**))) return value;
104 (*vars).tmpalloc = (*vars).tmpcnt * 2;
105 }
106 (*vars).tmp[(*vars).tmpcnt] = value;
107 (*vars).tmpcnt++;
108 return value;
109}
110
111/* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
112 varname, the printf-result will be added/appended to the varlist, if varname=NULL it will only be returned.
113 In either case you will always get a reference back which you may freely use (but you should not call
114 free/realloc on this as it will be automatically cleaned!)*/
115char *tpl_printf(struct templatevars *vars, uint8_t addmode, char *varname, char *fmtstring, ...) {
116 uint32_t needed;
117 char test[1];
118 va_list argptr;
119
120 va_start(argptr,fmtstring);
121 needed = vsnprintf(test, 1, fmtstring, argptr);
122 va_end(argptr);
123
124 char *result;
125 if (!cs_malloc(&result, needed + 1)) return "";
126 va_start(argptr,fmtstring);
127 vsnprintf(result, needed + 1, fmtstring, argptr);
128 va_end(argptr);
129
130 if (varname == NULL) tpl_addTmp(vars, result);
131 else {
132 char *tmp = tpl_addVar(vars, addmode, varname, result);
133 free(result);
134 result = tmp;
135 }
136 return result;
137}
138
139/* Returns the value for a name or an empty string if nothing was found. */
140char *tpl_getVar(struct templatevars *vars, char *name) {
141 int32_t i;
142 char *result = NULL;
143 for(i = (*vars).varscnt-1; i >= 0; --i) {
144 if (strcmp((*vars).names[i], name) == 0) {
145 result = (*vars).values[i];
146 break;
147 }
148 }
149 if (result == NULL) return "";
150 else {
151 if ((*vars).vartypes[i] == TPLADDONCE || (*vars).vartypes[i] == TPLAPPENDONCE) {
152 // This is a one-time-use variable which gets cleaned up automatically after retrieving it
153 if (!cs_malloc(&(*vars).values[i], 1)) {
154 (*vars).values[i] = result;
155 result[0] = '\0';
156 return result;
157 } else {
158 (*vars).values[i][0] = '\0';
159 return tpl_addTmp(vars, result);
160 }
161 } else return result;
162 }
163}
164
165/* Initializes all variables for a templatevar-structure and returns a pointer to it. Make
166 sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
167struct templatevars *tpl_create(void) {
168 struct templatevars *vars;
169 if (!cs_malloc(&vars, sizeof(struct templatevars))) return NULL;
170 (*vars).varsalloc = 64;
171 (*vars).varscnt = 0;
172 (*vars).tmpalloc = 64;
173 (*vars).tmpcnt = 0;
174 if (!cs_malloc(&(*vars).names, (*vars).varsalloc * sizeof(char**))) {
175 free(vars);
176 return NULL;
177 }
178 if (!cs_malloc(&(*vars).values, (*vars).varsalloc * sizeof(char**))) {
179 free((*vars).names);
180 free(vars);
181 return NULL;
182 }
183 if (!cs_malloc(&(*vars).vartypes, (*vars).varsalloc * sizeof(uint8_t*))) {
184 free((*vars).names);
185 free((*vars).values);
186 free(vars);
187 return NULL;
188 }
189 if (!cs_malloc(&(*vars).tmp, (*vars).tmpalloc * sizeof(char**))) {
190 free((*vars).names);
191 free((*vars).values);
192 free((*vars).vartypes);
193 free(vars);
194 return NULL;
195 }
196 return vars;
197}
198
199/* Clears all allocated memory for the specified templatevar-structure. */
200void tpl_clear(struct templatevars *vars) {
201 int32_t i;
202 for(i = (*vars).varscnt-1; i >= 0; --i) {
203 free((*vars).names[i]);
204 free((*vars).values[i]);
205 }
206 free((*vars).names);
207 free((*vars).values);
208 free((*vars).vartypes);
209 for(i = (*vars).tmpcnt-1; i >= 0; --i) {
210 free((*vars).tmp[i]);
211 }
212 free((*vars).tmp);
213 free(vars);
214}
215
216/* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
217char *tpl_getFilePathInSubdir(const char *path, const char* subdir, const char *name, const char* ext, char *result, uint32_t resultsize) {
218 int path_len = strlen(path);
219 const char *path_fixup = "";
220 if (path_len && path[path_len - 1] != '/')
221 path_fixup = "/";
222 if (path_len + strlen(path_fixup) + strlen(name) + strlen(subdir) + strlen(ext) < resultsize) {
223 snprintf(result, resultsize, "%s%s%s%s%s", path, path_fixup, subdir, name, ext);
224 } else result[0] = '\0';
225 return result;
226}
227
228char *tpl_getTplPath(const char *name, const char *path, char *result, uint32_t resultsize) {
229 return tpl_getFilePathInSubdir(path, "", name, ".tpl", result, resultsize);
230}
231
232#define check_conf(CONFIG_VAR, text) \
233 if (config_enabled(CONFIG_VAR) && strncmp(#CONFIG_VAR, text, len) == 0) { ok = 1; break; }
234
235/* Returns an unparsed template either from disk or from internal templates.
236 Note: You must free() the result after using it and you may get NULL if an error occured!*/
237char *tpl_getUnparsedTpl(const char* name, int8_t removeHeader, const char* subdir) {
238 int32_t i;
239 char *result;
240
241 if (cfg.http_tpl) {
242 char path[255];
243 if ((strlen(tpl_getFilePathInSubdir(cfg.http_tpl, subdir, name, ".tpl", path, 255)) > 0 && file_exists(path))
244 || (strlen(subdir) > 0
245#ifdef TOUCH
246 && strcmp(subdir, TOUCH_SUBDIR)
247#endif
248 && strlen(tpl_getFilePathInSubdir(cfg.http_tpl, "" , name, ".tpl", path, 255)) > 0 && file_exists(path)))
249 {
250 FILE *fp;
251 char buffer[1025];
252 memset(buffer, 0, sizeof(buffer));
253 int32_t readen, allocated = 1025, offset, size = 0;
254 if (!cs_malloc(&result, allocated)) return NULL;
255 if ((fp = fopen(path,"r"))!=NULL) {
256 // Use as read size sizeof(buffer) - 1 to ensure that buffer is
257 // zero terminated otherwise strstr can segfault!
258 while((readen = fread(buffer, 1, sizeof(buffer) - 1, fp)) > 0) {
259 offset = 0;
260 if (size == 0 && removeHeader) {
261 /* Remove version string from output and check if it is valid for output */
262 char *pch1 = strstr(buffer,"<!--OSCam");
263 if (pch1 != NULL) {
264 char *pch2 = strstr(pch1,"-->");
265 if (pch2 != NULL) {
266 offset = pch2 - buffer + 4;
267 readen -= offset;
268 pch2[0] = '\0';
269 char *ptr1, *ptr2, *saveptr1 = NULL, *saveptr2 = NULL;
270 for (i = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && i < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), i++)
271 {
272 if (i == 3 && strlen(ptr1) > 2) {
273 int8_t ok = 0;
274 for (ptr2 = strtok_r(ptr1, ",", &saveptr2); (ptr2) && ok == 0 ; ptr2 = strtok_r(NULL, ",", &saveptr2))
275 {
276 size_t len = strlen(ptr2);
277 check_conf(WITH_CARDREADER, ptr2);
278 check_conf(CARDREADER_PHOENIX, ptr2);
279 check_conf(CARDREADER_INTERNAL_AZBOX, ptr2);
280 check_conf(CARDREADER_INTERNAL_COOLAPI, ptr2);
281 check_conf(CARDREADER_INTERNAL_SCI, ptr2);
282 check_conf(CARDREADER_SC8IN1, ptr2);
283 check_conf(CARDREADER_MP35, ptr2);
284 check_conf(CARDREADER_SMARGO, ptr2);
285 check_conf(CARDREADER_PCSC, ptr2);
286 check_conf(CARDREADER_SMART, ptr2);
287 check_conf(CARDREADER_DB2COM, ptr2);
288 check_conf(CARDREADER_STAPI, ptr2);
289 check_conf(TOUCH, ptr2);
290 check_conf(CS_ANTICASC, ptr2);
291 check_conf(CS_CACHEEX, ptr2);
292 check_conf(HAVE_DVBAPI, ptr2);
293 check_conf(IPV6SUPPORT, ptr2);
294 check_conf(IRDETO_GUESSING, ptr2);
295 check_conf(LCDSUPPORT, ptr2);
296 check_conf(LEDSUPPORT, ptr2);
297 check_conf(MODULE_CAMD33, ptr2);
298 check_conf(MODULE_CAMD35, ptr2);
299 check_conf(MODULE_CAMD35_TCP, ptr2);
300 check_conf(MODULE_CCCAM, ptr2);
301 check_conf(MODULE_CCCSHARE, ptr2);
302 check_conf(MODULE_CONSTCW, ptr2);
303 check_conf(MODULE_GBOX, ptr2);
304 check_conf(MODULE_GHTTP, ptr2);
305 check_conf(MODULE_MONITOR, ptr2);
306 check_conf(MODULE_NEWCAMD, ptr2);
307 check_conf(MODULE_PANDORA, ptr2);
308 check_conf(MODULE_RADEGAST, ptr2);
309 check_conf(MODULE_SERIAL, ptr2);
310 check_conf(READER_BULCRYPT, ptr2);
311 check_conf(READER_CONAX, ptr2);
312 check_conf(READER_CRYPTOWORKS, ptr2);
313 check_conf(READER_GRIFFIN, ptr2);
314 check_conf(READER_DGCRYPT, ptr2);
315 check_conf(READER_DRE, ptr2);
316 check_conf(READER_IRDETO, ptr2);
317 check_conf(READER_NAGRA, ptr2);
318 check_conf(READER_SECA, ptr2);
319 check_conf(READER_TONGFANG, ptr2);
320 check_conf(READER_VIACCESS, ptr2);
321 check_conf(READER_VIDEOGUARD, ptr2);
322 check_conf(WITH_CARDREADER, ptr2);
323 check_conf(WITH_DEBUG, ptr2);
324 check_conf(WITH_LB, ptr2);
325 check_conf(WITH_LIBCRYPTO, ptr2);
326 check_conf(WITH_SSL, ptr2);
327 check_conf(WITH_STAPI, ptr2);
328 } // for
329 if (ok == 0) return result;
330 break;
331 } // if
332 } // for
333 } // if
334 } // if
335 } // if
336 if (allocated < size + readen + 1) {
337 allocated += size + 1024;
338 if (!cs_realloc(&result, allocated)) return NULL;
339 }
340 memcpy(result + size, buffer + offset, readen);
341 size += readen;
342 } // while
343 result[size] = '\0';
344 fclose (fp);
345 return result;
346 } // if
347 } // if
348 } // if
349
350 bool found = 0;
351 uint32_t name_hash = jhash(name, strlen(name));
352 for(i = 0; i < tpls_count; i++) {
353 if (tpls[i].tpl_name_hash == name_hash) {
354 found = 1;
355 break;
356 }
357 }
358
359 if (found) {
360 const struct tpl *tpl = &tpls[i];
361 if (!cs_malloc(&result, tpl->tpl_data_len + 1)) return NULL; // +1 to accomodate \0 at the end
362 memcpy(result, tpl->tpl_data, tpl->tpl_data_len);
363 } else {
364 if (!cs_malloc(&result, 1)) return NULL; // Return empty string
365 }
366 return result;
367}
368
369/* Returns the specified template with all variables/other templates replaced or an
370 empty string if the template doesn't exist. Do not free the result yourself, it
371 will get automatically cleaned up! */
372char *tpl_getTpl(struct templatevars *vars, const char* name) {
373 char *tplorg = tpl_getUnparsedTpl(name, 1, tpl_getVar(vars, "SUBDIR"));
374 if (!tplorg) return "";
375 char *tplend = tplorg + strlen(tplorg);
376 char *pch, *pch2, *tpl=tplorg;
377 char varname[33];
378
379 int32_t tmp,respos = 0;
380 int32_t allocated = 2 * strlen(tpl) + 1;
381 char *result;
382 if (!cs_malloc(&result, allocated)) return "";
383
384 while(tpl < tplend) {
385 if (tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#') {
386 pch2 = tpl;
387 pch = tpl + 2;
388 while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) ++pch;
389 if (pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#') {
390 memcpy(varname, pch2 + 2, pch - pch2 - 2);
391 varname[pch - pch2 - 2] = '\0';
392 if (strncmp(varname, "TPL", 3) == 0) {
393 if ((*vars).messages > 0 || strncmp(varname, "TPLMESSAGE", 10) != 0)
394 pch2 = tpl_getTpl(vars, varname + 3);
395 else pch2 = "";
396 } else {
397 pch2 = tpl_getVar(vars, varname);
398 }
399 tmp = strlen(pch2);
400 if (tmp + respos + 2 >= allocated) {
401 allocated = tmp + respos + 256;
402 if (!cs_realloc(&result, allocated)) return "";
403 }
404 memcpy(result + respos, pch2, tmp);
405 respos += tmp;
406 tpl = pch + 2;
407 }
408 } else {
409 if (respos + 2 >= allocated) {
410 allocated = respos + 256;
411 if (!cs_realloc(&result, allocated)) return "";
412 }
413 result[respos] = tpl[0];
414 ++respos;
415 ++tpl;
416 }
417 }
418 free(tplorg);
419 result[respos] = '\0';
420 tpl_addTmp(vars, result);
421 return result;
422}
423
424/* Saves all templates to the specified paths. Existing files will be overwritten! */
425int32_t tpl_saveIncludedTpls(const char *path) {
426 int32_t i, cnt = 0;
427 char tmp[256];
428 FILE *fp;
429 for (i = 0; i < tpls_count; ++i) {
430 const struct tpl *tpl = &tpls[i];
431 if (strlen(tpl_getTplPath(tpl->tpl_name, path, tmp, 256)) > 0 && (fp = fopen(tmp,"w")) != NULL) {
432 if (strncmp(tpl->tpl_name, "IC", 2) != 0) {
433 fprintf(fp, "<!--OSCam;%lu;%s;%s;%s-->\n", crc32(0L, (unsigned char *)tpl->tpl_data, tpl->tpl_data_len), CS_VERSION, CS_SVN_VERSION, tpl->tpl_deps);
434 }
435 fwrite(tpl->tpl_data, tpl->tpl_data_len, 1, fp);
436 fclose (fp);
437 ++cnt;
438 }
439 }
440 return cnt;
441}
442
443/* Checks all disk templates in a directory if they are still current or may need upgrade! */
444void tpl_checkOneDirDiskRevisions(const char* subdir) {
445 char dirpath[255] = "\0";
446 snprintf(dirpath, 255, "%s%s", cfg.http_tpl ? cfg.http_tpl : "", subdir);
447 int32_t i;
448 char path[255];
449 for(i = 0; i < tpls_count; ++i) {
450 const struct tpl *tpl = &tpls[i];
451 if (strncmp(tpl->tpl_name, "IC", 2) != 0 && strlen(tpl_getTplPath(tpl->tpl_name, dirpath, path, 255)) > 0 && file_exists(path)) {
452 int8_t error = 1;
453 char *tplorg = tpl_getUnparsedTpl(tpl->tpl_name, 0, subdir);
454 unsigned long checksum = 0, curchecksum = crc32(0L, (unsigned char*)tpl->tpl_data, tpl->tpl_data_len);
455 char *ifdefs = "", *pch1 = strstr(tplorg,"<!--OSCam");
456 if (pch1 != NULL) {
457 char *version = "?", *revision = "?";
458 char *pch2 = strstr(pch1,"-->");
459 if (pch2 != NULL) {
460 pch2[0] = '\0';
461 int32_t j;
462 char *ptr1, *saveptr1 = NULL;
463 for (j = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && j < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), j++) {
464 if (j == 0) checksum = strtoul(ptr1, NULL, 10);
465 else if (j == 1) version = ptr1;
466 else if (j == 2) revision = ptr1;
467 else if (j == 3) ifdefs = ptr1;
468 }
469 }
470 if (checksum != curchecksum) {
471 cs_log("WARNING: Your http disk template %s was created for an older revision of OSCam and was changed in original OSCam (%s,r%s). Please consider upgrading it!", path, version, revision);
472 } else error = 0;
473 } else cs_log("WARNING: Your http disk template %s is in the old template format without revision info. Please consider upgrading it!", path);
474 if (error) cs_log("If you are sure that it is current, add the following line at the beginning of the template to suppress this warning: <!--OSCam;%lu;%s;%s;%s-->", curchecksum, CS_VERSION, CS_SVN_VERSION, ifdefs);
475 free(tplorg);
476 }
477 }
478}
479
480/* Checks whether disk templates need upgrade - including sub-directories */
481void tpl_checkDiskRevisions(void) {
482 char subdir[255];
483 char dirpath[255];
484 if (cfg.http_tpl) {
485 tpl_checkOneDirDiskRevisions("");
486 DIR *hdir;
487 struct dirent entry;
488 struct dirent *result;
489 struct stat s;
490 if ((hdir = opendir(cfg.http_tpl)) != NULL) {
491 while(cs_readdir_r(hdir, &entry, &result) == 0 && result != NULL) {
492 if (strcmp(".", entry.d_name) == 0 || strcmp("..", entry.d_name) == 0) {
493 continue;
494 }
495 snprintf(dirpath, 255, "%s%s", cfg.http_tpl, entry.d_name);
496 if (stat(dirpath, &s) == 0) {
497 if (s.st_mode & S_IFDIR) {
498 snprintf(subdir, 255,
499 #ifdef WIN32
500 "%s\\"
501 #else
502 "%s/"
503 #endif
504 , entry.d_name);
505 tpl_checkOneDirDiskRevisions(subdir);
506 }
507 }
508 }
509 closedir(hdir);
510 }
511 }
512}
513
514/* Helper function for urldecode.*/
515static int32_t x2i(int32_t i) {
516 i = toupper(i);
517 i = i - '0';
518 if (i > 9) i = i - 'A' + '9' + 1;
519 return i;
520}
521
522/* Decodes values in a http url. Note: The original value is modified! */
523void urldecode(char *s) {
524 int32_t c, c1, n;
525 char *t;
526 t = s;
527 n = strlen(s);
528 while(n >0) {
529 c = *s++;
530 if (c == '+') c = ' ';
531 else if (c == '%' && n > 2) {
532 c = *s++;
533 c1 = c;
534 c = *s++;
535 c = 16*x2i(c1) + x2i(c);
536 n -= 2;
537 }
538 *t++ = c;
539 n--;
540 }
541 *t = 0;
542}
543
544/* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
545char *urlencode(struct templatevars *vars, char *str) {
546 char *buf;
547 if (!cs_malloc(&buf, strlen(str) * 3 + 1)) return "";
548 char *pstr = str, *pbuf = buf;
549 while (*pstr) {
550 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') *pbuf++ = *pstr;
551 else if (*pstr == ' ') *pbuf++ = '+';
552 else {
553 *pbuf++ = '%';
554 *pbuf++ = to_hex(*pstr >> 4);
555 *pbuf++ = to_hex(*pstr & 15);
556 }
557 ++pstr;
558 }
559 *pbuf = '\0';
560 /* Allocate the needed memory size and store it in the templatevars */
561 if (!cs_realloc(&buf, strlen(buf) + 1)) return "";
562 return tpl_addTmp(vars, buf);
563}
564
565/* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
566 Do not call free() or realloc on the returned reference or you will get memory corruption! */
567char *xml_encode(struct templatevars *vars, char *chartoencode) {
568 if (!chartoencode) return "";
569 int32_t i, pos = 0, len = strlen(chartoencode);
570 char *encoded;
571 char buffer[7];
572 /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
573 if (!cs_malloc(&encoded, len * 6 + 1)) return "";
574 for (i = 0; i < len; ++i) {
575 unsigned char tmp = chartoencode[i];
576 switch(tmp) {
577 case '&' : memcpy(encoded + pos, "&amp;", 5); pos += 5; break;
578 case '<' : memcpy(encoded + pos, "&lt;", 4); pos += 4; break;
579 case '>' : memcpy(encoded + pos, "&gt;", 4); pos += 4; break;
580 case '"' : memcpy(encoded + pos, "&quot;", 6); pos += 6; break;
581 case '\'': memcpy(encoded + pos, "&#39;", 5); pos += 5; break; // &apos; not supported on older IE
582 case '\n': memcpy(encoded + pos, "\n", 1); pos += 1; break;
583 default:
584 if (tmp < 32 || (cs_http_use_utf8 != 1 && tmp > 127)) {
585 snprintf(buffer, 7, "&#%d;", tmp);
586 memcpy(encoded + pos, buffer, strlen(buffer));
587 pos += strlen(buffer);
588 } else {
589 encoded[pos] = tmp;
590 ++pos;
591 }
592 }
593 }
594 /* Reduce to the really needed memory size and store it in the templatevars */
595 if (!cs_realloc(&encoded, pos + 1)) return "";
596 encoded[pos] = '\0';
597 return tpl_addTmp(vars, encoded);
598}
599
600/* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
601char *sec2timeformat(struct templatevars *vars, int32_t seconds) {
602 char *value;
603 if (seconds <= 0)
604 return "00:00:00";
605 if (!cs_malloc(&value, 16))
606 return "00:00:00";
607 int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
608 secs = seconds % 60;
609 if (seconds >= 60) {
610 fullmins = seconds / 60;
611 mins = fullmins % 60;
612 if (fullmins >= 60) {
613 fullhours = fullmins / 60;
614 hours = fullhours % 24;
615 days = fullhours / 24;
616 }
617 }
618 if (days == 0)
619 snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs);
620 else
621 snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs);
622 return tpl_addTmp(vars, value);
623}
624
625#endif
Note: See TracBrowser for help on using the repository browser.