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

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

webif: Create and use private templates array.

This allows storing of additional information along with templates
data (which is const).

For now we store name hash but in the future the data that comes from
struct templates (in webif/pages.c) may need to be preprocessed
(uncompressed for example) and the abstraction in this commit makes
it easier to do such changes.

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.