1 /*
2  * Copyright 1999-2006 University of Chicago
3  * 
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  * 
8  * http://www.apache.org/licenses/LICENSE-2.0
9  * 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "globus_common.h"
18 #include "libxml/xmlreader.h"
19 #include <string.h>
20 #include <fcntl.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 #include <errno.h>
24
25 #define TEMPLATE_NODE                   "tmpl"
26 #define EVAL_NODE                       "eval"
27 #define SCRIPT_NODE                     "script"
28
29 #define BEGIN_PRINT                     "\nprint(\""
30 #define BEGIN_PRINT_LENGTH              8
31 #define END_PRINT                       "\");\n"
32 #define END_PRINT_LENGTH                4
33 #define PRINT_LENGTH                    12
34
35 #define BEGIN_EPRINT                    "\nprint("
36 #define BEGIN_EPRINT_LENGTH             7
37 #define END_EPRINT                      ");\n"
38 #define END_EPRINT_LENGTH               3
39 #define EPRINT_LENGTH                   10
40
41 #define DELIMITER_COUNT                 2
42 static const char *                     DELIMITERS = "\n\"";
43 static const char *                     REPLACEMENTS[DELIMITER_COUNT] = 
44                                         {"\\n", "\\\""};
45
46 /**
47  * Functions for parsing the template file
48  */
49
50 static
51 const char *
52 my_strpbrk(
53     const char *                        str,
54     size_t                              str_length,
55     int *                               locator_index,
56     const char *                        delims,
57     int *                               delim_index,
58     int                                 escape);
59
60 static
61 int
62 globus_i_template_convert_chars(
63     const char *                        old_buffer,
64     size_t                              old_length,
65     char **                             buffer,
66     size_t *                            length,
67     int                                 delim_count,
68     const char *                        delim_set,
69     const char **                       replace_set);
70
71 int
72 globus_wsdl_template_get_jsbuf(
73     const char *                        filename,
74     char **                             buffer,
75     size_t *                            length,
76     char **                             error_string,
77     char                                script_token,
78     char                                eval_token)
79 0 {
80 0     size_t                              read_length = 0;
81 0     char                                read_buffer[1000];
82 0     size_t                              new_length = 0;
83 0     char *                              new_buffer = NULL;
84 0     size_t                              tmp_length = 0;
85 0     char *                              tmp_buffer = NULL;
86 0     size_t                              script_length = 0;
87 0     size_t                              eval_length = 0;
88 0     size_t                              tmpl_length = 0;
89 0     const char *                        loc;
90 0     const char *                        prev;
91 0     char                                charset[3];
92 0     size_t                              template_length = 0;
93 0     char *                              template_buffer = NULL;
94 0     int                                 infd;
95 0     int                                 in_script = 0;
96 0     int                                 in_eval = 0;
97 0     char                                token;
98 0     int                                 loc_index, loc_length;
99 0     int                                 delim_index;
100 0     int                                 add_loc_index = 0;
101
102 0     *error_string = NULL;
103 0     charset[0] = script_token;
104 0     charset[1] = eval_token;
105 0     charset[2] = 0;
106
107 0     infd = open(filename, O_RDONLY, 0);
108 0     if(infd < 0)
109     {
110 /** XXX - this should be changed to use globus errno error calls */
111 0         char *                          error_message;
112 0         error_message = strerror(errno);
113 0         *error_string = globus_libc_strdup(error_message); 
114 0         goto exit;
115     }
116
117 0     memset(read_buffer, 0, 1000);
118
119 0     while((read_length = read(infd, read_buffer, 1000)) > 0)
120     {
121 0         tmp_buffer = realloc(tmp_buffer, tmp_length + read_length);
122 0         if(!tmp_buffer)
123         {
124 /** XXX - this should be fixed to use globus_error_errno calls */
125 0             char *                      error_message;
126 0             error_message = strerror(errno);
127 0             *error_string = globus_libc_strdup(error_message);
128 0             goto exit;
129         }
130         
131 0         memcpy(tmp_buffer + tmp_length, read_buffer, read_length);
132 0         tmp_length += read_length;
133     }
134
135 0     tmp_buffer = realloc(tmp_buffer, tmp_length + 1);
136 0     tmp_buffer[tmp_length] = 0;
137
138 0     loc = tmp_buffer;
139 0     loc_length = tmp_length;
140 0     prev = tmp_buffer;
141
142 0     while(1)
143     {
144 0         loc = my_strpbrk(loc, loc_length, &loc_index, charset, &delim_index, 1);
145 0         if(!loc)
146         {
147 0             if(in_script)
148             {
149 0                 *error_string = globus_libc_strdup(
150                     "End of file reached inside a script chunk");
151 0                 goto exit;
152             }
153
154 0             if(in_eval)
155             {
156 0                 *error_string = globus_libc_strdup(
157                     "End of file reached inside an evalu chunk");
158 0                 goto exit;
159             }
160
161 0             tmpl_length = loc_length;
162 0             globus_i_template_convert_chars(
163                 prev, tmpl_length,
164                 &template_buffer, &template_length,
165                 DELIMITER_COUNT,
166                 DELIMITERS, 
167                 REPLACEMENTS);
168 0             new_buffer = realloc(
169                 new_buffer,
170                 new_length + template_length + PRINT_LENGTH);
171 0             memcpy(new_buffer + new_length, 
172                    BEGIN_PRINT, BEGIN_PRINT_LENGTH);
173 0             memcpy(new_buffer + new_length + BEGIN_PRINT_LENGTH,
174                    template_buffer, template_length);
175 0             memcpy(new_buffer + new_length + 
176                    BEGIN_PRINT_LENGTH + template_length, 
177                    END_PRINT, END_PRINT_LENGTH);
178 0             new_length += PRINT_LENGTH + template_length;
179
180 0             free(template_buffer);
181 0             template_buffer = NULL;
182
183 0             break;
184         }
185
186 0         if(add_loc_index > 0)
187         {
188 0             loc_index += add_loc_index + 1;
189 0             add_loc_index = 0;
190         }
191
192 0         if(loc_index != 0 && (*(loc - 1) == '\\'))
193         {
194 0             add_loc_index = loc_index;
195 0             ++loc;
196 0             continue;
197         }
198
199 0         loc_length -= (loc_index + 1);
200
201 0         token = *loc;
202         
203 0         if(token == script_token)
204         {
205 0             if(in_eval)
206             {
207 0                 *error_string = malloc(500);
208 0                 sprintf(*error_string,
209                         "While parsing %s: Found a script token (%c), "
210                         "expected an eval token (%c)",
211                         filename, script_token, eval_token);
212 0                 goto exit;
213             }
214
215 0             if(in_script)
216             {
217 0                 in_script = 0;
218
219 0                 script_length = loc_index;
220 0                 new_buffer = realloc(new_buffer, new_length + script_length);
221 0                 memcpy(new_buffer + new_length, prev, script_length);
222 0                 new_length += script_length;
223             }
224             else
225             {
226 0                 in_script = 1;
227                 
228 0                 tmpl_length = loc_index;
229 0                 globus_i_template_convert_chars(
230                     prev, tmpl_length,
231                     &template_buffer, &template_length, 
232                     DELIMITER_COUNT,
233                     DELIMITERS,
234                     REPLACEMENTS);
235 0                 new_buffer = realloc(
236                     new_buffer,
237                     new_length + template_length + PRINT_LENGTH);
238 0                 memcpy(new_buffer + new_length, 
239                        BEGIN_PRINT, BEGIN_PRINT_LENGTH);
240 0                 memcpy(new_buffer + new_length + BEGIN_PRINT_LENGTH,
241                        template_buffer, template_length);
242 0                 memcpy(new_buffer + new_length + 
243                        BEGIN_PRINT_LENGTH + template_length, 
244                        END_PRINT, END_PRINT_LENGTH);
245 0                 new_length += PRINT_LENGTH + template_length;
246
247 0                 free(template_buffer);
248 0                 template_buffer = NULL;
249             }
250         }
251 0         else if(token == eval_token)
252         {
253 0             if(in_script)
254             {
255 0                 *error_string = malloc(500);
256 0                 sprintf(
257                     *error_string,
258                     "While parsing %s: Found an eval token (%c), "
259                     "expected a script token (%c)",
260                     filename, eval_token, script_token);
261 0                 goto exit;
262             }
263
264 0             if(in_eval)
265             {
266 0                 in_eval = 0;
267
268 0                 eval_length = loc_index;
269 0                 new_buffer = realloc(new_buffer, 
270                                      new_length + eval_length + EPRINT_LENGTH);
271 0                 memcpy(new_buffer + new_length, BEGIN_EPRINT, 
272                        BEGIN_EPRINT_LENGTH);
273 0                 memcpy(new_buffer + new_length + BEGIN_EPRINT_LENGTH,
274                        prev, eval_length);
275 0                 memcpy(new_buffer + new_length + 
276                        BEGIN_EPRINT_LENGTH + eval_length, 
277                        END_EPRINT, END_EPRINT_LENGTH);
278 0                 new_length += EPRINT_LENGTH + eval_length;
279             }
280             else
281             {
282 0                 in_eval = 1;
283
284 0                 tmpl_length = loc_index;
285 0                 globus_i_template_convert_chars(
286                     prev, tmpl_length,
287                     &template_buffer, &template_length, 
288                     DELIMITER_COUNT,
289                     DELIMITERS,
290                     REPLACEMENTS);
291 0                 new_buffer = realloc(
292                     new_buffer,
293                     new_length + template_length + PRINT_LENGTH);
294 0                 memcpy(new_buffer + new_length, 
295                        BEGIN_PRINT, BEGIN_PRINT_LENGTH);
296 0                 memcpy(new_buffer + new_length + BEGIN_PRINT_LENGTH,
297                        template_buffer, template_length);
298 0                 memcpy(new_buffer + new_length + 
299                        BEGIN_PRINT_LENGTH + template_length, 
300                        END_PRINT, END_PRINT_LENGTH);
301 0                 new_length += PRINT_LENGTH + template_length;
302
303 0                 free(template_buffer);
304 0                 template_buffer = NULL;
305             }
306         }
307
308 0         if(loc_length >= 0)
309         {
310 0             ++loc;
311 0             prev = loc;
312         }
313         else
314         {
315 0             break;
316         }
317     }
318
319 0     new_buffer = realloc(new_buffer, new_length + 2);
320 0     memcpy(new_buffer + new_length, "\r\n", 2);
321 0     new_length += 2;
322     
323 0     *buffer = new_buffer;
324 0     *length = new_length;
325
326   exit:
327
328 0     if(infd > 0)
329     {
330 0         close(infd);
331     }
332
333 0     if(*error_string)
334     {
335 0         return -1;
336     }
337
338 0     return 0;
339 }
340
341
342 /* int */
343 /* globus_wsdl_xml_template_get_jsbuf( */
344 /*     const char *                        filename, */
345 /*     char **                             buffer, */
346 /*     size_t *                            length, */
347 /*     char **                             error_string) */
348 /* { */
349 /*     size_t                              new_length = 0; */
350 /*     xmlTextReaderPtr                    reader = NULL; */
351 /*     char *                              new_buffer = NULL; */
352
353 /*     reader = xmlNewTextReaderFilename(filename); */
354 /*     if(!reader) */
355 /*     { */
356 /*         xmlErrorPtr                     error; */
357 /*         char *                          error_message; */
358
359 /*         error = xmlGetLastError(); */
360 /*         if(!error) */
361 /*         { */
362 /*             return -1; */
363 /*         } */
364
365 /*         error_message = malloc(strlen(error->message) + 500); */
366 /*         if(!error_message) */
367 /*         { */
368 /*             return -1; */
369 /*         } */
370         
371 /*         sprintf(error_message, "Could not parse template: %s: %s",  */
372 /*                 filename, error->message); */
373 /*         *error_string = error_message; */
374 /*         return -1; */
375 /*     } */
376
377 /*     while(xmlTextReaderRead(reader) > 0) */
378 /*     { */
379 /*         const xmlChar *                 local_name; */
380
381 /*         local_name = xmlTextReaderConstLocalName(reader); */
382 /*         if(xmlStrEqual(local_name, TEMPLATE_NODE)) */
383 /*         { */
384 /*             int                         bufflen; */
385 /*             char *                      template_buffer; */
386 /*             xmlNodePtr                  node; */
387
388 /*             node = xmlTextReaderExpand(reader); */
389 /*             if(node) */
390 /*             { */
391 /*                 node = node->children; */
392 /*             } */
393
394 /*             while(node) */
395 /*             { */
396 /*                 if(node->type == XML_TEXT_NODE) */
397 /*                 { */
398 /*                     if(node->content) */
399 /*                     { */
400 /*                         size_t          template_length; */
401
402 /*                         globus_i_template_convert_chars( */
403 /*                             node->content, strlen(node->content), */
404 /*                             &template_buffer, &template_length,  */
405 /*                             '\n', "\\n"); */
406 /*                         bufflen = template_length + 12; */
407 /*                         new_buffer = realloc(new_buffer, new_length + bufflen); */
408 /*                         memcpy(new_buffer + new_length, "\nprint(\"", 8); */
409 /*                         memcpy(new_buffer + new_length + 8,  */
410 /*                                template_buffer, template_length); */
411 /*                         memcpy(new_buffer + new_length + 8 + template_length, */
412 /*                                "\");\n", 4); */
413 /*                         new_length += bufflen; */
414 /*                     } */
415 /*                 } */
416                 
417 /*                 node = node->next; */
418 /*             } */
419 /*         } */
420 /*         else if(xmlStrEqual(local_name, EVAL_NODE)) */
421 /*         { */
422 /*             int                         bufflen; */
423 /*             size_t                      eval_length; */
424 /*             const xmlChar *             eval_buffer; */
425 /*             xmlNodePtr                  node; */
426
427 /*             node = xmlTextReaderExpand(reader); */
428 /*             if(node) */
429 /*             { */
430 /*                 node = node->children; */
431 /*             } */
432
433 /*             while(node) */
434 /*             { */
435 /*                 if(node->type == XML_TEXT_NODE) */
436 /*                 { */
437 /*                     eval_buffer = node->content; */
438 /*                     if(eval_buffer) */
439 /*                     { */
440 /*                         eval_length = strlen(eval_buffer); */
441 /*                         bufflen = eval_length + 10; */
442 /*                         new_buffer = realloc(new_buffer, new_length + bufflen); */
443 /*                         memcpy(new_buffer + new_length, "\nprint(", 7); */
444 /*                         memcpy(new_buffer + new_length + 7,  */
445 /*                                eval_buffer, eval_length); */
446 /*                         memcpy(new_buffer + new_length + 7 + eval_length, */
447 /*                                ");\n", 3); */
448 /*                         new_length += bufflen; */
449 /*                     } */
450 /*                 } */
451
452 /*                 node = node->next; */
453 /*             } */
454 /*         } */
455 /*         else if(xmlStrEqual(local_name, SCRIPT_NODE)) */
456 /*         { */
457 /*             size_t                      script_length; */
458 /*             const xmlChar *             script_buffer; */
459 /*             xmlNodePtr                  node; */
460
461 /*             node = xmlTextReaderExpand(reader); */
462 /*             if(node) */
463 /*             { */
464 /*                 node = node->children; */
465 /*             } */
466
467 /*             while(node) */
468 /*             { */
469 /*                 if(node->type == XML_TEXT_NODE) */
470 /*                 { */
471 /*                     script_buffer = node->content; */
472 /*                     if(script_buffer) */
473 /*                     { */
474 /*                         script_length = strlen(script_buffer); */
475 /*                         new_buffer = realloc(new_buffer,  */
476 /*                                              new_length + script_length); */
477 /*                         memcpy(new_buffer + new_length,  */
478 /*                                script_buffer, script_length); */
479 /*                         new_length += script_length; */
480 /*                     } */
481 /*                 } */
482
483 /*                 node = node->next; */
484 /*             } */
485 /*         } */
486 /*     } */
487
488 /*     new_buffer = realloc(new_buffer, new_length + 1); */
489 /*     memcpy(new_buffer + new_length, "\0", 1); */
490 /*     new_length += 1; */
491
492 /*     *buffer = new_buffer; */
493 /*     *length = new_length; */
494 /*     return 0; */
495 /* }         */
496
497 static
498 const char *
499 my_strpbrk(
500     const char *                        str,
501     size_t                              str_length,
502     int *                               locator_index,
503     const char *                        delims,
504     int *                               delim_index,
505     int                                 escape)
506 0 {
507 0     const char *                        locator;
508 0     int                                 delim_count, ind, i;
509
510 0     ind = 0;
511 0     i = 0;
512 0     delim_count = strlen(delims);
513 0     locator = str;
514 0     while(*locator && ind < str_length)
515     {
516 0         for(i = 0; i < delim_count; ++i)
517         {
518 0             if(*locator == delims[i])
519             {
520 0                 if(escape &&
521                    (ind != 0 && (*(locator - 1) == '\\')))
522                 {
523 0                     continue;
524                 }
525
526 0                 if(locator_index)
527                 {
528 0                     *locator_index = ind;
529                 }
530
531 0                 if(delim_index)
532                 {
533 0                     *delim_index = i;
534                 }
535 0                 return locator;
536             }
537         }
538         
539 0         locator++;
540 0         ind++;
541     }
542
543 0     if(locator_index)
544     {
545 0         *locator_index = -1;
546     }
547 0     return NULL;
548 }
549
550 static
551 int
552 globus_i_template_convert_chars(
553     const char *                        tmp_buffer,
554     size_t                              tmp_length,
555     char **                             buffer,
556     size_t *                            length,
557     int                                 delim_count,
558     const char *                        delim_set,
559     const char **                       replace_set)
560 0 {
561 0     const char *                        locator;
562 0     const char *                        prev;
563 0     char *                              new_buffer = NULL;
564 0     size_t                              new_length = 0;
565 0     int                                 upto_length, locator_length; 
566 0     int                                 replace_length;
567 0     int                                 found_index, delim_index;
568
569 0     locator = tmp_buffer;
570 0     locator_length = tmp_length;
571 0     prev = tmp_buffer;
572 0     while(1)
573     {
574 0         if(locator_length <= 0)
575         {
576 0             break;
577         }
578
579 0         locator = my_strpbrk(locator, locator_length, &found_index, delim_set, &delim_index, 0);
580 0         if(!locator)
581         {
582 0             upto_length = locator_length;
583 0             new_buffer = realloc(new_buffer, new_length + upto_length);
584 0             memcpy(new_buffer + new_length, prev, upto_length);
585 0             new_length += upto_length;
586 0             break;
587         }
588
589 0         upto_length = found_index;
590 0         locator_length -= (found_index + 1);
591
592 0         replace_length = strlen(replace_set[delim_index]);
593 0         new_buffer = realloc(new_buffer, 
594                              new_length + replace_length + upto_length);
595 0         memcpy(new_buffer + new_length, prev, upto_length);
596 0         memcpy(new_buffer + new_length + upto_length, replace_set[delim_index],
597                replace_length);
598 0         new_length += upto_length + replace_length;
599
600 0         locator++;
601 0         prev = locator;
602         
603     }
604
605 0     *buffer = new_buffer;
606 0     *length = new_length;
607
608 0     return 0;