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

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

webif: Do not store images in templates array as base64.

Save a little bit of binary size.

This commit introduces no user visible changes.

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