1 /***************************************************************************
2 * Copyright (C) 2007 by Jesus Arias Fisteus *
3 * jaf@it.uc3m.es *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21 /*
22 * dtd_util.c
23 *
24 * (Jes�s Arias Fisteus)
25 *
26 * Funciones para acceder a la informaci�n codificada de los
27 * DTD de XHTML en dtd.c y dtd.h
28 *
29 * Hay funciones de b�squeda de elementos y atributos por
30 * su nombre y de comprobaci�n de contenido de elementos
31 * y de valores de atributos...
32 *
33 *
34 */
35
36 #include <stdio.h>
37 #include <string.h>
38
39 #include "xchar.h"
40 #include "mensajes.h"
41 #include "dtd.h"
42 #include "dtd_util.h"
43
44
45 extern char *tree_strdup(const char *str);
46
47 /* tabla hash para buscar nombres de entidades */
48 extern int ent_hash[];
49
50
51 /* funciones internas */
52 static int is_child_valid(int *rule_ptr, int elements[], int num);
53 static int search_par_close(int rule_ptr);
54 static int hash_value(const char *cad);
55 static int dtd_ref_is_valid(xchar *ref);
56
57 static int isXmlChar(xchar ch);
58 static int isXmlNameChar(xchar ch);
59 static int isXmlLetter(xchar ch);
60 static int makeXmlCdata(xchar *value);
61 static int makeXmlId(xchar *value);
62 static int makeXmlNmtoken(xchar *value);
63 static int makeXmlNames(xchar *value, int atttype);
64
65
66 /*
67 * devuelve el �ndice (n�mero) del dtd cuya clave (key)
68 * coincida con la proporcionada
69 *
70 */
dtd_get_dtd_index(const char * key)71 int dtd_get_dtd_index(const char *key)
72 {
73 int i;
74 int dtd= -1;
75
76 for (i=0; i<DTD_NUM; i++) {
77 if (!strncmp(key, dtd_key[i], DTD_KEY_LEN)) {
78 dtd = i;
79 break;
80 }
81 }
82
83 return dtd;
84 }
85
86
87 /*
88 * devuelve el �ndice (n�mero) del dtd cuya clave (key)
89 * coincida con la proporcionada
90 *
91 */
dtd_get_dtd_index_n(const char * key,size_t key_length)92 int dtd_get_dtd_index_n(const char *key, size_t key_length)
93 {
94 int i;
95 int dtd= -1;
96
97 for (i=0; i<DTD_NUM; i++) {
98 if (key_length == strlen(dtd_key[i])
99 && !strncmp(key, dtd_key[i], key_length)) {
100 dtd = i;
101 break;
102 }
103 }
104
105 return dtd;
106 }
107
108
109 /*
110 * busca un elemento por nombre y devuelve
111 * su identificador
112 *
113 */
dtd_elm_search(const char * elm_name)114 int dtd_elm_search(const char *elm_name)
115 {
116 int i;
117
118 for (i=0; i<elm_data_num;i++)
119 if (!strcmp(elm_list[i].name, elm_name)) return i;
120
121 /* si no sali� antes, no se encuentra */
122 return -1;
123 }
124
125
126 /*
127 * devuelve un puntero a la referencia a entidad o -1 si no se encuentra
128 * ent_name llega como '&nombre;'
129 *
130 */
dtd_ent_search(const char * ent_name)131 int dtd_ent_search(const char *ent_name)
132 {
133 char *ent;
134 int hash;
135 int indice;
136 int i;
137
138 /* duplica la cadena y se queda con 'nombre' */
139 ent= tree_strdup(&ent_name[1]);
140 for (i = 0; ent[i] != ';'; i++);
141 ent[i]=0;
142
143 /* b�squeda con tabla hash */
144 hash= hash_value(ent);
145 for (indice=-1, i=ent_hash[hash]; (i<ent_hash[hash+1]) && (indice==-1); i++)
146 if (!strcmp(ent,ent_list[i])) indice= i;
147
148 /* free(ent); */
149 return indice;
150 }
151
152
153
154
155 /*
156 * busca un atributo por nombre en la lista de atributos,
157 * comenzando por el id siguiente a 'from'. Devuelve
158 * el identificador del atributo o -1 si no se encuentra
159 *
160 */
dtd_att_search(const char * att_name,int from)161 int dtd_att_search(const char *att_name, int from)
162 {
163 int i;
164
165 for (i=from+1; i<att_data_num;i++)
166 if (!strcmp(att_list[i].name, att_name)) return i;
167
168 /* si no sali� antes, no se encuentra */
169 return -1;
170 }
171
172
173
174
175 /*
176 * busca un atributo con nombre 'att_name'
177 * en la lista de atributos dada por 'in'
178 *
179 * devuelve -1 si no est�, o el �ndice del atributo
180 *
181 */
dtd_att_search_list(const char * att_name,const int * in)182 int dtd_att_search_list(const char *att_name, const int *in)
183 {
184 int i;
185
186 for (i=0; (i<ELM_ATTLIST_LEN) && (in[i]>=0); i++) {
187 if (!strcmp(att_name, att_list[in[i]].name)) return in[i];
188 }
189 return -1;
190 }
191
192
193
194 /*
195 * busca un atributo con id 'att_id'
196 * en la lista de atributos dada por 'in'
197 *
198 * devuelve -1 si no est�, o el �ndice del atributo
199 *
200 */
dtd_att_search_list_id(int att_id,const int * in)201 int dtd_att_search_list_id(int att_id, const int *in)
202 {
203 int i;
204
205 for (i=0; (i<ELM_ATTLIST_LEN) && (in[i]>=0); i++) {
206 if (in[i]==att_id) return in[i];
207 }
208 return -1;
209 }
210
211
212
213
214 /*
215 * comprueba si el valor de un atributo es v�lido
216 *
217 * devuelve 1 si el valor cumple con las especificaciones
218 * del DTD o 0 si no
219 * devuelve 2 si cumple, pero necesita ser transformado a
220 * min�sculas
221 *
222 * COMPROBACIONES:
223 * - CDATA, ID, IDREF, IDREFS, NMTOKEN, NMTOKENS: comprueba que
224 * los caracteres usados sean v�lidos para ese tipo. Si no
225 * lo son, los pisa con '_'.
226 *
227 * - enumerated: comprueba que el valor est� en la enumeraci�n de
228 * posibles valores. Si no, lo pasa a min�sculas y vuelve
229 * a comprobar.
230 *
231 *
232 */
dtd_att_is_valid(int att_id,xchar * value)233 int dtd_att_is_valid(int att_id, xchar *value)
234 {
235 att_data_t *att;
236
237 att = &att_list[att_id];
238 return dtd_att_is_valid_by_type(att->attType, att->defaultDecl,
239 att->defaults, value);
240 }
241
dtd_att_is_valid_by_type(int att_type,defaultDecl_t default_decl,int defaults,xchar * value)242 int dtd_att_is_valid_by_type(int att_type, defaultDecl_t default_decl,
243 int defaults, xchar *value)
244 {
245 char *valores;
246 char str[256];
247 int valid;
248
249 /*
250 * si contenttype>=0, tenemos una lista de posibles valores
251 * y se comprueba si est� entre ellos
252 *
253 */
254 if (att_type>=0) {
255 int i,k;
256
257 valores= dtd_att_read_buffer(att_type);
258
259 /* valores[0] es '(' */
260 i= 1;
261 valid=0;
262 while (valores[i]) {
263 for (k=0; (valores[i]!='|') && (valores[i]!=')'); i++,k++)
264 str[k]= valores[i];
265 str[k]= 0; /* termina la cadena */
266 i++; /* salta el '|'o ')'*/
267
268 /* comprueba este valor */
269 if (!strcmp(str,value)) {
270 valid=1;
271 break;
272 } else {
273 xchar lowercase[128];
274 xtolower(lowercase,value,128);
275 if (!strcmp(str,lowercase)) {
276 valid=2;
277 break;
278 }
279 }
280 } /* while */
281
282 if (valid != 1) return valid;
283 } /* if */
284 else {
285 /* se comprueba que no contenga & o <
286 * puede ser v�lido a�n conteniendo & si
287 * forma parte de una referencia
288 */
289 if (dtd_att_val_search_errors(value)!=-1) return 0;
290
291 } /* else */
292
293
294
295 /*
296 * se comprueba que el valor respete la sintaxis
297 * asociada a su tipo
298 *
299 */
300 switch (att_type) {
301 case ATTTYPE_CDATA:
302 if (!makeXmlCdata(value)) return 0;
303 break;
304 case ATTTYPE_ID:
305 case ATTTYPE_IDREF:
306 if (!makeXmlId(value)) return 0;
307 break;
308 case ATTTYPE_NMTOKEN:
309 if (!makeXmlNmtoken(value)) return 0;
310 break;
311 case ATTTYPE_IDREFS:
312 case ATTTYPE_NMTOKENS:
313 if (!makeXmlNames(value,att_type)) return 0;
314 break;
315 }
316
317
318 /*
319 * ahora se comprueba si hay declaraci�n FIXED, en cuyo
320 * caso tenemos que comprobar que adquiera ese valor
321 *
322 */
323 if (default_decl==DEFDECL_FIXED) {
324 if (!strcmp(value,dtd_att_read_buffer(defaults))) return 1;
325 else {
326 xchar lowercase[128];
327 xtolower(lowercase,value,128);
328 if (!strcmp(lowercase,dtd_att_read_buffer(defaults))) return 1;
329 else return 0;
330 }
331 }
332
333 return 1;
334 }
335
336
337
338
339
340 /**
341 * comprueba el valor de un atributo desde el
342 * punto de vista de aparici�n de caracteres ilegales
343 * ('<' o '&' que no pertenezca a referencia a entidad)
344 *
345 * devuelve la posici�n en que se encuentre '<' o '&'
346 *
347 * o -1 si todo es correcto
348 *
349 */
dtd_att_val_search_errors(const xchar * value)350 int dtd_att_val_search_errors(const xchar *value)
351 {
352 int i;
353 xchar *v= tree_strdup(value);
354
355 for (i=0; v[i]; i++) {
356 if (v[i]=='<') {/*free(v);*/return i;}
357 else if (v[i]=='&') {
358 int k;
359 for (k=i+1; v[k]; k++)
360 if (v[k]==';') {
361 xchar tmp= v[k+1];
362 v[k+1]= 0;
363 if (!dtd_ref_is_valid(&v[i])) {/*free(v);*/return i;}
364 else {
365 v[k+1]= tmp;
366 break;
367 }
368 }
369 if (!v[k]) {/*free(v);*/return i;}
370 }
371 } /* for */
372
373 /* free(v); */
374 return -1;
375 }
376
377
378
379
380
381 /*
382 * lee una cadena de caracteres del buffer de elementos
383 *
384 */
dtd_elm_read_buffer(int buff_ptr)385 char *dtd_elm_read_buffer(int buff_ptr)
386 {
387 if (buff_ptr < 0) return NULL;
388 if (buff_ptr > elm_buffer_num) return NULL;
389
390 return (char*) &elm_buffer[buff_ptr];
391 }
392
393
394
395 /*
396 * lee una cadena de caracteres del buffer de atributos
397 *
398 */
dtd_att_read_buffer(int buff_ptr)399 char *dtd_att_read_buffer(int buff_ptr)
400 {
401 if (buff_ptr < 0) return NULL;
402 if (buff_ptr > att_buffer_num) return NULL;
403
404 return (char*) &att_buffer[buff_ptr];
405 }
406
407
408
409
410
411
412 /*
413 * comprueba si la secuencia identificadores de elemento
414 * concuerda con la regla de tipo 'child' dada por el
415 * puntero.
416 *
417 * la secuencia 'elements' es un array de identificadores ordenada
418 * el n�mero de elementos del array lo indica 'num'
419 * el puntero a la regla es 'rule_ptr'
420 *
421 * DEVUELVE: 1 si lo es o 0 si no lo es (-1 si lo podr�a ser con
422 * m�s elementos)
423 *
424 */
dtd_is_child_valid(int rule_ptr,int elements[],int num)425 int dtd_is_child_valid(int rule_ptr, int elements[], int num)
426 {
427 int rule;
428 int valid;
429
430 DEBUG("dtd_is_child_valid()");
431
432 rule= rule_ptr;
433 valid=is_child_valid(&rule, elements, num);
434
435 EPRINTF2(" c�digo retornado: %d [regla %d]\n",valid,rule);
436
437 if (valid==num) return 1;
438 else if (valid==-2) return -1; /* no v�lido, pero por falta de elm */
439
440 /* no v�lido */
441 else return 0;
442 }
443
444
445
446 /*
447 * comprueba si el elemento child_id puede ser hijo de father_id
448 *
449 * devuelve 1 si lo puede ser o 0 si no
450 *
451 * para tipo children, s�lo comprueba que dicho elemento
452 * est� dentro de su cadena
453 *
454 */
dtd_can_be_child(int child,int father,int dtd_num)455 int dtd_can_be_child(int child, int father, int dtd_num)
456 {
457 int i;
458
459 if (elm_list[father].contenttype[dtd_num]==CONTTYPE_ANY)
460 return 1;
461
462 if (elm_list[father].contenttype[dtd_num]==CONTTYPE_EMPTY)
463 return 0;
464
465 /* es children o mixed */
466 for (i= elm_list[father].contentspec[dtd_num];elm_buffer[i]; i++)
467 if ((elm_buffer[i] & CSPEC_ELM_MASK)&&
468 ((elm_buffer[i]& ~CSPEC_ELM_MASK)==child))
469 return 1;
470
471 return 0;
472 }
473
474
475
476 /*
477 * comprueba si el elemento elm es de tipo bloque
478 *
479 * devuelve 1 es de bloque; 0 si es inline
480 *
481 */
dtd_elm_is_block(int elm)482 int dtd_elm_is_block(int elm)
483 {
484
485 /* es de bloque si no puede aparecer dentro de un p�rrafo */
486 return ! dtd_can_be_child(elm, ELMID_P, XHTML_TRANSITIONAL);
487 }
488
489
490
491
492
493
494
495 /*
496 * ==================================================================
497 * FUNCIONES INTERNAS
498 * ==================================================================
499 *
500 */
501
502
503
504 /*
505 *
506 * funci�n recursiva en la que se basa el funcionamiento de
507 * dtd_is_child_valid()
508 *
509 * devuelve: <0: no es v�lido
510 * num: es v�lido con 'num' elementos coincidentes
511 *
512 */
is_child_valid(int * rule_ptr,int elements[],int num)513 static int is_child_valid(int *rule_ptr, int elements[], int num)
514 {
515 unsigned char data;
516 int is_choice;
517 int repeat;
518 int rule;
519 int elm;
520 int valid = -1;
521 int elm_matched;
522 int error_code;
523 int coincide_choice;
524
525 #ifdef CHILD_DEBUG
526 char str[1024];
527 int len_buff= 0;
528 int i;
529 #endif
530
531 DEBUG("is_child_valid()");
532
533 #ifdef CHILD_DEBUG
534 EPRINTF2(" rule: %d; num: %d;\n", *rule_ptr, num);
535 EPRINTF1(" %s\n", contentspecToString(&elm_buffer[*rule_ptr], str,
536 CONTTYPE_CHILDREN, &len_buff));
537 EPRINTF(" :: ");
538 for (i=0; i<num; i++)
539 EPRINTF1("%s ", elm_list[elements[i]].name);
540 EPRINTF("\n");
541 #endif
542
543 coincide_choice= 0;
544 error_code= -1;
545 rule= *rule_ptr;
546 data= elm_buffer[rule];
547
548 if (!CSPEC_ISPAR(data) || (!(data & CSPEC_PAR_O)))
549 EXIT("dtd_is_child_valid: the rule must begin with '('");
550
551 is_choice= CSPEC_ISCHOICE(data);
552 repeat= CSPEC_NUM(data);
553
554 #ifdef CHILD_DEBUG
555 if (is_choice) EPRINTF(" | ");
556 else EPRINTF(" , ");
557 switch (repeat) {
558 case CSPEC_AST:
559 EPRINTF("*\n");
560 break;
561 case CSPEC_MAS:
562 EPRINTF("+\n");
563 break;
564 case CSPEC_INT:
565 EPRINTF("?\n");
566 break;
567 default:
568 EPRINTF("1\n");
569 break;
570 }
571 #endif
572
573 elm= 0;
574 elm_matched= 0;
575 data= elm_buffer[++rule];
576 for ( ; ; data= elm_buffer[++rule]) {
577
578 /* mira si es v�lido el elemento actual */
579 if (CSPEC_ISELM(data)) {
580 /* es un elemento suelto */
581 if ((elm<num) && elements[elm]==CSPEC_ELM(data)) valid= 1;
582 else if (elm>=num) valid=-2; /* faltan elementos */
583 else valid= -1;
584 #ifdef CHILD_DEBUG
585 EPRINTF3(" . [%d:%d] %s\n",rule,valid,elm_list[CSPEC_ELM(data)].name);
586 #endif
587
588 } else if (data & CSPEC_PAR_O) {
589 /* es una regla compuesta: comienza con '(' */
590 #ifdef CHILD_DEBUG
591 int rule0= rule;
592 EPRINTF1(" >> [%d]\n",rule);
593 #endif
594 valid= is_child_valid(&rule, elements+elm, num-elm);
595 #ifdef CHILD_DEBUG
596 EPRINTF3(" << [%d:%d] %s\n",rule,valid,
597 contentspecToString(&elm_buffer[rule0], str,
598 CONTTYPE_CHILDREN, &len_buff));
599 EPRINTF1(" -> %s\n",
600 contentspecToString(&elm_buffer[rule+1], str,
601 CONTTYPE_CHILDREN, &len_buff));
602 #endif
603
604 } else if (data & CSPEC_PAR_C) {
605 /* fin de esta regla */
606
607 #ifdef CHILD_DEBUG
608 EPRINTF2(" )) coincide_choice:%d; elm_matched:%d\n",
609 coincide_choice, elm_matched);
610 #endif
611
612 if (is_choice) {
613 /* error si no hubo coincidencias en iteraciones anteriores
614 * y el tipo no permite 0 coincidencias
615 */
616 *rule_ptr= rule;
617 if ((coincide_choice)||(elm_matched>0)
618 ||(repeat==CSPEC_INT)||(repeat==CSPEC_AST))
619 return elm_matched;
620 else return error_code;
621 } else {
622 /* si no es choice, se cumple */
623 elm_matched= elm;
624
625 /* retorna si s�lo permite una coincidenecia */
626 if ((repeat==CSPEC_INT)||(repeat==0)) {
627 *rule_ptr= rule;
628 return elm_matched;
629 } else {
630 /* vuelve a verificar */
631 rule= *rule_ptr;
632 #ifdef CHILD_DEBUG
633 EPRINTF(" --R--\n");
634 #endif
635 continue;
636 }
637 }
638 } else EXIT("is_child_valid: incorrect rule");
639
640
641
642 /* comprueba el resultado de este elemento */
643 if (valid>=0) {
644
645 #ifdef CHILD_DEBUG
646 EPRINTF1(" --V-- %d\n", valid);
647 #endif
648
649 /* OK, se mira el siguiente elemento (si no es CHOICE) o se finaliza */
650 elm+= valid;
651
652 /* si es choice, busca el fin y retorna */
653 if (is_choice) {
654 elm_matched= elm;
655 coincide_choice= 1;
656
657 /* si no se emparej� ninguno,
658 * aunque sea v�lido, se contin�a con el siguiente */
659 if (elm_matched) {
660 /* si es '*' o '+', o contin�a el bucle */
661 if ((!repeat)||(repeat==CSPEC_INT)) {
662 rule= search_par_close(rule+1);
663 *rule_ptr= rule;
664 return elm;
665 }
666 else rule= *rule_ptr;
667 }
668 }
669
670 /* no es choice,
671 * o es choice v�lido sin emparejar ning�n elemento
672 * ==> se mira si cumple el siguiente elemento
673 */
674
675 } else {
676 /* no v�lido */
677 /* si no es choice retorna con error */
678
679 #ifdef CHILD_DEBUG
680 EPRINTF1(" --NV-- %d\n", valid);
681 #endif
682
683 if (!is_choice) {
684 rule= search_par_close(rule+1);
685 *rule_ptr= rule;
686
687 /* error si no hubo coincidencias en iteraciones anteriores
688 * y el tipo no permite 0 coincidencias
689 */
690 if ((elm_matched>0)||(repeat==CSPEC_INT)||(repeat==CSPEC_AST))
691 return elm_matched; /* no hay error */
692 else return valid; /* hay error */
693 }
694
695 /* es choice, se sigue probando */
696 if (valid==-2) error_code= -2;
697 }
698 } /* for */
699
700 }
701
702
703
704
705
search_par_close(int rule_ptr)706 static int search_par_close(int rule_ptr)
707 {
708 int num_par;
709 unsigned char data;
710
711 data= elm_buffer[rule_ptr];
712 for( num_par=0; !CSPEC_ISPAR(data) || (num_par>0) || !(data & CSPEC_PAR_C) ;
713 data=elm_buffer[++rule_ptr]) {
714 if (CSPEC_ISPAR(data) && (data & CSPEC_PAR_C)) num_par--;
715 else if (CSPEC_ISPAR(data) && (data & CSPEC_PAR_O)) num_par++;
716 }
717
718 return rule_ptr;
719 }
720
721
722
723
hash_value(const char * cad)724 static int hash_value(const char *cad)
725 {
726 int i;
727 int hash=0;
728
729 for (i=0; cad[i]; i++)
730 hash= (hash*31 + cad[i]) & 0xff; /* %256 */
731
732 return hash;
733 }
734
735
736
737
738 /**
739 * comprueba que una referencia sea v�lida
740 * llega como 'á' o 'ō'
741 *
742 * devuelve 1 si es v�lida o 0 si no
743 *
744 */
dtd_ref_is_valid(xchar * ref)745 static int dtd_ref_is_valid(xchar *ref)
746 {
747 if ((ref[0]!='&')||(ref[strlen(ref)-1]!=';')) return 0;
748
749 if (ref[1]=='#') {
750 /* referencia a car�cter */
751 int hexa;
752 int i;
753
754 if (ref[2]=='x') hexa= 1;
755 else hexa= 0;
756
757 for (i= hexa+2; ref[i]!=';'; i++) {
758 if (((ref[i]<'0')||(ref[i]>'9')) &&
759 (!hexa || (
760 ((ref[i]<'a')||(ref[i]>'f'))
761 && ((ref[i]<'A')||(ref[i]>'F')))))
762 return 0;
763 }
764 } else /* referencia a entidad */
765 if (dtd_ent_search(ref) == -1) return 0;
766
767 return 1;
768 }
769
770
771
772 /*
773 * comprueba que el valor sea CDATA de XML
774 *
775 * los caracteres que no lo cumplan son pisados con '_'
776 *
777 */
makeXmlCdata(xchar * value)778 static int makeXmlCdata(xchar *value)
779 {
780 int i;
781
782 /* verifica si cumple: Char* */
783 for (i=0; value[i];i++)
784 if (!isXmlChar(value[i])) value[i]='_';
785
786 return 1;
787 }
788
789
790
791
792 /*
793 * comprueba que el valor sea un ID o IDREF de XML
794 *
795 * los caracteres que no lo cumplan son pisados con '_'
796 *
797 */
makeXmlId(xchar * value)798 static int makeXmlId(xchar *value)
799 {
800 /* ID e IDREF: (Name)= (Letter | '_' | ':') (NameChar)* */
801 int i;
802
803 if (!value[0]) return 0;
804
805 /*
806 * da problemas cambiar el valor del identificador, porque
807 * los enlaces se rompen. Se prefiere que �ste sea eliminado
808 *
809 */
810 #if 0
811 /* primer car�cter: Letter | '_' | ':' */
812 if ((value[0]!='_')&&(value[0]!=':')&&(!isXmlLetter(value[0])))
813 value[0]= '_';
814
815 /* el resto: NameChar* */
816 for (i=1; value[i];i++)
817 if (!isXmlNameChar(value[i])) value[i]='_';
818 #endif
819
820 /* primer car�cter: Letter | '_' | ':' */
821 if ((value[0]!='_')&&(value[0]!=':')&&(!isXmlLetter(value[0])))
822 return 0;
823
824 /* el resto: NameChar* */
825 for (i=1; value[i];i++)
826 if (!isXmlNameChar(value[i])) return 0;
827
828
829
830 return 1;
831 }
832
833
834 /*
835 * comprueba que el valor sea un NMTOKEN de XML
836 *
837 * los caracteres que no lo cumplan son pisados con '_'
838 *
839 */
makeXmlNmtoken(xchar * value)840 static int makeXmlNmtoken(xchar *value)
841 {
842 /* NMTOKEN: Nmtoken= (NameChar)* */
843 int i;
844
845 if (!value[0]) return 0;
846
847 /* NameChar* */
848 for (i=0; value[i];i++)
849 if (!isXmlNameChar(value[i])) value[i]='_';
850
851 return 1;
852 }
853
854
855 /*
856 * comprueba el valor de un atributo de tipo
857 * IDREFS y NMTOKENS
858 *
859 */
makeXmlNames(xchar * value,int atttype)860 static int makeXmlNames(xchar *value, int atttype)
861 {
862 xchar *ini,*fin;
863 xchar tmp;
864
865 ini= value;
866 fin= value;
867
868 while (1) {
869 for ( ;
870 (*fin) && (*fin!=0x20) && (*fin!=0x09)
871 && (*fin!=0x0a) && (*fin!=0x0d);
872 fin++);
873 tmp= *fin;
874 *fin= 0;
875
876 switch (atttype) {
877 case ATTTYPE_IDREFS:
878 if (!makeXmlId(ini)) {*fin= tmp; return 0;}
879 break;
880 case ATTTYPE_NMTOKENS:
881 if (!makeXmlNmtoken(ini)) {*fin= tmp; return 0;}
882 break;
883 default:
884 *fin= tmp;
885 return 0;
886 }
887
888 *fin= tmp;
889
890 for ( ;
891 (*fin) && ((*fin==0x20) || (*fin==0x09)
892 || (*fin==0x0a) || (*fin==0x0d));
893 fin++);
894 ini= fin;
895 if (!*fin) break;
896 }
897
898 return 1;
899 }
900
901
902
903
904
905
906
907
908 /*
909 * comprueba si el car�cter es Char seg�n XML
910 *
911 * devuelve 1 si lo es o 0 si no
912 *
913 */
isXmlChar(xchar ch)914 static int isXmlChar(xchar ch)
915 {
916 if ((ch>=0x20) || (ch=0x09) || (ch=0x0a) || (ch=0x0d))
917 return 1;
918 else return 0;
919 }
920
921
922 /*
923 * comprueba si el car�cter es Letter seg�n XML
924 *
925 * devuelve 1 si lo es o 0 si no
926 *
927 */
isXmlLetter(xchar ch)928 static int isXmlLetter(xchar ch)
929 {
930 if (((ch>=0x41)&&(ch<=0x5A)) ||
931 ((ch>=0x61)&&(ch<=0x7A)) ||
932 ((ch>=(char)0xC0)&&(ch<=(char)0xD6)) ||
933 ((ch>=(char)0xD8)&&(ch<=(char)0xF6)) ||
934 ((ch>=(char)0xF8) /*&&(ch<=0xFF)*/ ))
935 /* comentado porque con char es siempre cierto */
936 return 1;
937 else return 0;
938 }
939
940
941 /*
942 * comprueba si el car�cter es NameChar seg�n XML
943 *
944 * devuelve 1 si lo es o 0 si no
945 *
946 */
isXmlNameChar(xchar ch)947 static int isXmlNameChar(xchar ch)
948 {
949 if (((ch>=0x41)&&(ch<=0x5A)) || /* Letter */
950 ((ch>=0x61)&&(ch<=0x7A)) ||
951 ((ch>=(char)0xC0)&&(ch<=(char)0xD6)) ||
952 ((ch>=(char)0xD8)&&(ch<=(char)0xF6)) ||
953 ((ch>=(char)0xF8)/*&&(ch<=0xFF)*/) ||
954 ((ch>=(char)0xF8)/*&&(ch<=0xFF)*/) ||
955 ((ch>=0x30)&&(ch<=0x39)) || /* Digit */
956 (ch==(char)0xB7) || /* Extender */
957 (ch=='.') || (ch=='-') ||
958 (ch==':') || (ch=='_'))
959 return 1;
960 else return 0;
961 }
962
963
964
965
966
967 /* funci�n recursiva que pasa a la cadena el contentspec del buffer */
contentspecToString(char * buff,char * str,contentType_t conttype,int * len_buff)968 char *contentspecToString(char *buff, char *str, contentType_t conttype,int *len_buff)
969 {
970 unsigned char v;
971 int i;
972
973 switch (conttype) {
974 case CONTTYPE_NONE:
975 strcpy(str,"No definido");
976 *len_buff= 0;
977 break;
978 case CONTTYPE_EMPTY:
979 strcpy(str,"EMPTY");
980 *len_buff= 0;
981 break;
982 case CONTTYPE_ANY:
983 strcpy(str,"ANY");
984 *len_buff= 0;
985 break;
986 case CONTTYPE_MIXED:
987 {
988 strcpy(str,"(#PCDATA");
989 for (i=0; buff[i]; i++) {
990 strcat(str,"|");
991 strcat(str,elm_list[buff[i]&(~CSPEC_ELM_MASK)].name);
992 }
993
994 strcat(str,")");
995 }
996 *len_buff= i;
997 break;
998
999 case CONTTYPE_CHILDREN:
1000 {
1001 char separador[2];
1002 int num_items, avance;
1003
1004 i= 0;
1005 num_items= 0;
1006
1007 v= buff[i++];
1008 if (!(v&CSPEC_ELM_MASK)&&((v&CSPEC_PAR_MASK)!=CSPEC_PAR_O)) {
1009 strcpy(str,"<error>");
1010 break;
1011 }
1012
1013 if (v&CSPEC_CHOICE) strcpy(separador,"|"); /* choice */
1014 else strcpy(separador,","); /* enumerate */
1015
1016 strcpy(str,"(");
1017
1018 while ((((v=buff[i++])&CSPEC_PAR_MASK)!=CSPEC_PAR_C)
1019 || (v&CSPEC_ELM_MASK)) {
1020 if (num_items) strcat(str,separador);
1021 num_items++;
1022
1023 if (!(v&CSPEC_ELM_MASK)&&((v&CSPEC_PAR_MASK)==CSPEC_PAR_O)) {
1024 /* recursion */
1025 contentspecToString(&buff[i-1],str+strlen(str),conttype,&avance);
1026 /* busca donde acaba */
1027 /*
1028 for ( ; ((buff[i]&CSPEC_PAR_MASK)!=CSPEC_PAR_C)
1029 ||(buff[i]&CSPEC_ELM_MASK); i++);
1030 i++;
1031 */
1032 i+= avance-1;
1033 } else {
1034 /* elemento aislado */
1035 if (!(v&CSPEC_ELM_MASK)) {
1036 strcat(str,"<error>");
1037 break;
1038 }
1039 strcat(str,elm_list[v&(~CSPEC_ELM_MASK)].name);
1040 }
1041 }
1042
1043 strcat(str,")");
1044 switch (buff[0]& CSPEC_NUM_MASK) {
1045 case CSPEC_AST:
1046 strcat(str,"*");
1047 break;
1048 case CSPEC_INT:
1049 strcat(str,"?");
1050 break;
1051 case CSPEC_MAS:
1052 strcat(str,"+");
1053 break;
1054 }
1055
1056 *len_buff= i;
1057 }
1058 } /* switch (conttype) */
1059
1060 return str;
1061 }
1062