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

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

webif: Fix possible segfault when template is read from disk.

strstr() can segfault if the data read in the buffer is not \0
terminated. This can happend if try to read binary file.

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