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 '&aacute;' o '&#333;'
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