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

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

webif: Compress built-in templates.

Use the minilzo code that we already have to compress the built-in
templates. This saves ~90k binary size on 32bit defconfig. As the
tool reports:

Compressed 148820 template bytes into 51619 bytes. 97201 saved bytes (65.31%).

The old code that works with non-compressed templates is still here,
to use it, comment #define USE_COMPRESSION 1 in webif/pages_gen.c
and recompile.

Once we establish that template compression works fine the old
code can be removed.

This commit introduces no user visible changes.

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