/**
 * \file XMLStructure.cpp
 * Classe de description d'une structure XML.
 * 
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "AllocateurMemoire.h"
#include "AllocateurXMLTag.h"
#include "AllocateurXMLProperty.h"

#include "XMLStructure.h"
#include "Exclusions.h"
#include "Inclusions.h"
#include "XMLTag.h"
#include "XMLProperty.h"
#include "FileUtils.h"
#include "FileLoader.h"
#include "TagReference.h"
#include "Array.h"

static TagReference *tableauReferencesTag(FileLoader *f,int *nb,AllocateurMemoire *amn,AllocateurMemoire *amc,Exclusions *exclusions);
static TagReference *tableauReferencesTag(FileLoader *f,int *nb,AllocateurMemoire *am,Inclusions *inclusions);
static TagReference *tableauReferencesTag(FileLoader *f,int *nb,char **ts,int ns,AllocateurMemoire *am);
static XMLTag *construction(TagReference *ttr,size_t *pos,size_t max,short *niveau,FileLoader *f,AllocateurMemoire *am,AllocateurXMLTag *at,AllocateurXMLProperty *ap,AllocateurMemoire *amtt,AllocateurMemoire *ampp,int texteInline);

static const size_t MOINS1 =(size_t) -1;

enum {
  OUVRANT = 1,
  FERMANT = 2,
  OUVRANT_FERMANT = 3 };

/**
 * Constructeur pour un nouvel objet XMLStructure.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::XMLStructure(void) {
  tag = NULL;
  am = NULL;
  amtt = NULL;
  amtp = NULL;
  at = NULL;
  ap = NULL;
}

/**
 * Constructeur pour un nouvel objet XMLStructure.
 *
 * @param filename Le nom du fichier de chargement.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::XMLStructure(char *filename) {
  FileLoader *file = new FileLoader(filename);
  tag = NULL;
  am = new AllocateurMemoire(1000000);
  amtt = new AllocateurMemoire(1000000);
  amtp = new AllocateurMemoire(1000000);
  at = new AllocateurXMLTag(100000);
  ap = new AllocateurXMLProperty(100000);
  int nb;
  AllocateurMemoire *amn = new AllocateurMemoire(1000000);
  AllocateurMemoire *amc = new AllocateurMemoire(1000000);
  TagReference *ttr = tableauReferencesTag(file,&nb,amn,amc,(Exclusions *) NULL);
  size_t pos = 0;
  short niveau = 0;
  printf("****** %s\n",filename);
  tag = construction(ttr,&pos,nb,&niveau,file,am,at,ap,amtt,amtp,1);
  printf("******\n");
  printf("%12d\n",am->getNombreAllocations());
  printf("%12lld\n",(long long) am->getUsedMemory());
  printf("%12d\n",at->getNombreXMLTagAlloues());
  printf("%12lld\n",(long long) at->getUsedMemory());
  printf("%12d\n",ap->getNombreXMLPropertyAlloues());
  printf("%12lld\n",(long long) ap->getUsedMemory());
  printf("-----------------\n");
  printf("%12lld\n",(long long) am->getUsedMemory()+at->getUsedMemory()+ap->getUsedMemory());
  printf("-----------------\n");
  delete(file);
  delete [] ttr;
  delete(amn);
  delete(amc);
}

/**
 * Constructeur pour un nouvel objet XMLStructure.
 *
 * @param filename Le nom du fichier de chargement.
 * @param exclusions Les exclusions de chargement.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::XMLStructure(char *filename,Exclusions *exclusions,int texteInline) {
  am = new AllocateurMemoire(20000);
  amtt = new AllocateurMemoire(20000);
  amtp = new AllocateurMemoire(10000);
  at = new AllocateurXMLTag(10000);
  ap = new AllocateurXMLProperty(10000);
  printf("\n%s\n\n",filename);
  FileLoader *file = new FileLoader(filename);
  tag = NULL;
  int nb;
  AllocateurMemoire *amn = new AllocateurMemoire(10000);
  AllocateurMemoire *amc = new AllocateurMemoire(10000);
  TagReference *ttr = tableauReferencesTag(file,&nb,amn,amc,exclusions);
  size_t pos = 0;
  short niveau = 0;
  printf("****** %s\n",filename);
  tag = construction(ttr,&pos,nb,&niveau,file,am,at,ap,amtt,amtp,texteInline);
  printf("******\n");
  printf("%12lld",(long long) am->getUsedMemory());
  printf("%12lld",(long long) at->getUsedMemory());
  printf("%12lld",(long long) ap->getUsedMemory());
  printf("%12lld",(long long) file->getUsedMemory());
  printf("%12lld",(long long) nb*sizeof(TagReference));
  printf("%12lld",(long long) amtt->getUsedMemory());
  printf("%12lld",(long long) amtp->getUsedMemory());
  printf("%12lld",(long long) amn->getUsedMemory());
  printf("%12lld\n",(long long) amc->getUsedMemory());
  printf("%12ld",(long) am->getUsedHandles());
  printf("%12ld",(long) at->getUsedHandles());
  printf("%12ld",(long) ap->getUsedHandles());
  printf("%12ld",(long) file->getUsedHandles());
  printf("%12ld",(long) 1);
  printf("%12ld",(long) amtt->getUsedHandles());
  printf("%12ld",(long) amtp->getUsedHandles());
  printf("%12ld",(long) amn->getUsedHandles());
  printf("%12ld\n",(long) amc->getUsedHandles());
  printf("-----------------\n");
  printf("%12lld\n",(long long) amtt->getUsedMemory()+amtp->getUsedMemory()+amn->getUsedMemory()+amc->getUsedMemory()+am->getUsedMemory()+at->getUsedMemory()+ap->getUsedMemory()+file->getUsedMemory()+nb*sizeof(TagReference));
  printf("%12lld\n",(long long) amtt->getUsedHandles()+amtp->getUsedHandles()+amn->getUsedHandles()+amc->getUsedHandles()+am->getUsedHandles()+at->getUsedHandles()+ap->getUsedHandles()+file->getUsedHandles()+1);
  printf("-----------------\n");
  printf("%12lld\n",(long long) amtt->getUsedMemory()+amtp->getUsedMemory()+am->getUsedMemory()+at->getUsedMemory()+ap->getUsedMemory());
  printf("%12lld\n",(long long) amtt->getUsedHandles()+amtp->getUsedHandles()+am->getUsedHandles()+at->getUsedHandles()+ap->getUsedHandles());
  printf("-----------------\n");
  delete(file);
  delete [] ttr;
  delete(amn);
  delete(amc);
}

/**
 * Constructeur pour un nouvel objet XMLStructure.
 *
 * @param filename Le nom du fichier de chargement.
 * @param inclusions Les inclusions de chargement.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::XMLStructure(char *filename,Inclusions *inclusions) {
  FileLoader *file = new FileLoader(filename);
  tag = NULL;
  am = new AllocateurMemoire(1000000);
  amtt = new AllocateurMemoire(1000000);
  amtp = new AllocateurMemoire(1000000);
  at = new AllocateurXMLTag(100000);
  ap = new AllocateurXMLProperty(100000);
  int nb;
  AllocateurMemoire *am2 = new AllocateurMemoire(1000000);
  TagReference *ttr = tableauReferencesTag(file,&nb,am2,inclusions);
  size_t pos = 0;
  short niveau = 0;
  printf("****** %s\n",filename);
  tag = construction(ttr,&pos,nb,&niveau,file,am,at,ap,amtt,amtp,1);
  printf("******\n");
  printf("%12d\n",am->getNombreAllocations());
  printf("%12lld\n",(long long) am->getUsedMemory());
  printf("%12d\n",at->getNombreXMLTagAlloues());
  printf("%12lld\n",(long long) at->getUsedMemory());
  printf("%12d\n",ap->getNombreXMLPropertyAlloues());
  printf("%12lld\n",(long long) ap->getUsedMemory());
  printf("-----------------\n");
  printf("%12lld\n",(long long) am->getUsedMemory()+at->getUsedMemory()+ap->getUsedMemory());
  printf("-----------------\n");
  delete(file);
  delete [] ttr;
  delete(am2);
}

/**
 * Constructeur pour un nouvel objet XMLStructure.
 *
 * @param filename Le nom du fichier de chargement.
 * @param ts Le tableau des chaines de caracteres de recherche.
 * @param ns Le nombre de chaines de caracteres de recherche.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::XMLStructure(char *filename,char **ts,int ns) {
  FileLoader *file = new FileLoader(filename);
  tag = NULL;
  am = new AllocateurMemoire(1000000);
  amtt = new AllocateurMemoire(1000000);
  amtp = new AllocateurMemoire(1000000);
  at = new AllocateurXMLTag(100000);
  ap = new AllocateurXMLProperty(100000);
  int nb;
  TagReference *ttr = tableauReferencesTag(file,&nb,ts,ns,am);
  if ( !ttr ) {
    tag = NULL;
    return; }
  size_t pos = 0;
  short niveau = 0;
  tag = construction(ttr,&pos,nb,&niveau,file,am,at,ap,amtt,amtp,1);
  delete(file);
  delete [] ttr;
}

/**
 * Destructeur pour un objet XMLStructure.
 *
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLStructure::~XMLStructure() {
  //if ( tag)
  //  delete(tag);
  if ( amtt )
    delete(amtt);
  if ( amtp )
    delete(amtp);
  if ( am )
    delete(am);
  if ( at )
    delete(at);
  if ( ap )
    delete(ap);
}

/**
 * Retour du tag racine.
 *
 * @return Le tag racine.
 * @author Nicolas Janey
 * @author nicolas.janey@univ-fcomte.fr
 * @version 1.0, 01/01/10
 */
XMLTag *XMLStructure::getTag(void) {
  return(tag);
}

static int nombreTag(FileLoader *file) {
  int cpt1 = 0;
  int cpt2 = 0;
  for (size_t i = 0 ; i < file->size ; i++ ) {
    if ( file->tc(i) == '>' )
      cpt1++;
    if ( file->tc(i) == '<' )
      cpt2++; }
  if ( cpt1 == cpt2 )
    return(cpt1);
  return(-1);
}

static char *extraction(AllocateurMemoire *am,FileLoader *file ,size_t pi,size_t pf) {
  char *name =(char *) am->myalloc((int) (pf-pi+2));
  for ( size_t i = 0 ; i < pf-pi+1 ; i++ )
    name[i] = file->tc(pi+i);
  name[pf-pi+1] = 0x00;
  return(name);
}

static TagReference *tableauReferencesTag(FileLoader *file,int *nbTag,AllocateurMemoire *amn,AllocateurMemoire *amc,Exclusions *exclusions) {
  int exclu = 0;
  char liste[40960];
  memset(liste,0,40960);
  int lp[10240];
  memset(lp,0,10240);
  int np = 0;
  int sp = 0;
  *nbTag = nombreTag(file);
  size_t pi = 0;
  size_t pf = 0;
  TagReference *ttr = new TagReference[*nbTag];
  int i = 0;
  int ii = 0;
  while ( i < *nbTag ) {
    size_t tpi;
    size_t tpf;
    size_t tnext;
    size_t tlast;
    unsigned char ttype = 0x00;
    char *tname = NULL;
    char *tcontenu = NULL;
    while ( file->tc(pi) != '<' )
      pi++;
    pf = pi+1;
    while ( file->tc(pf) != '>' )
      pf++;
    tpi = pi;
    tpf = pf;
    tnext = pf+1;
    while ( ( tnext < file->size ) && ( file->tc(tnext) != '<' ) )
      tnext++;
    tlast = pi-1;
    if ( pi != 0 )
      while ( ( tlast != 0 ) && ( file->tc(tlast) != '>' ) ) {
        tlast--; }
    size_t p1 = pi+1;
    while ( file->tc(p1) == ' ' )
      p1++;
    if ( file->tc(p1) == '/' ) {
      ttype = FERMANT;
      p1++; }
    size_t p2 = p1;
    while ( ( file->tc(p2) != ' ' ) && ( file->tc(p2) != '>' ) && ( file->tc(p2) != '/' ) )
      p2++;
    p2--;
    size_t p3 = pf-1;
    while ( file->tc(p3) == ' ' )
      p3--;
    if ( file->tc(p3) == '/' )
      ttype = OUVRANT_FERMANT;
    if ( !ttype )
      ttype = OUVRANT;
    tname = extraction(amn,file,p1,p2);
    if ( ttype == OUVRANT ) {
      lp[np] = sp;
      np++;
      if ( np != 1 ) {
        strcat(liste,",");
        sp++; }
      strcat(liste,tname);
      sp +=(int) strlen(tname);
      if ( exclusions )
        exclu = exclusions->estPresent(liste); }
    if ( ttype == FERMANT ) {
      if ( exclusions )
        exclu = exclusions->estPresent(liste);
      np--;
      sp = lp[np];
      liste[sp] = 0x00; }
    ttr[i].type = ttype;
    ttr[i].pi = tpi;
    ttr[i].pf = tpf;
    ttr[i].pnext = tnext;
    ttr[i].plast = tlast;
    ttr[i].setName(tname);
    if ( p3 > p2 ) {
      p2++;
      while ( file->tc(p2) == ' ' )
        p2++;
      if ( file->tc(p3) == '/' )
        p3--;
      while ( file->tc(p3) == ' ' )
        p3--;
      tcontenu = extraction(amc,file,p2,p3);
      ttr[i].setContenu(tcontenu); }
    pi = pf+1;
    i++;
    if ( exclu ) {
      i--;
      amc->stepBack();
      amn->stepBack();
      ttr[i].contenu = NULL;
      (*nbTag)--; }
      else {
      ii++; } }
  *nbTag = ii;
  TagReference *res = new TagReference[ii];
  for ( int ij = 0 ; ij < ii ; ij++ )
    res[ij] = ttr[ij];
  delete [] ttr;
  return(res);
}

static TagReference *tableauReferencesTag(FileLoader *file,int *nbTag,AllocateurMemoire *am,Inclusions *inclusions) {
  int inclu = 0;
  char liste[40960];
  memset(liste,0,40960);
  int lp[10240];
  memset(lp,0,10240);
  int np = 0;
  int sp = 0;
  *nbTag = nombreTag(file);
  size_t pi = 0;
  size_t pf = 0;
  TagReference *ttr = new TagReference[*nbTag];
  int i = 0;
  int ii = 0;
  while ( i < *nbTag ) {
    size_t tpi;
    size_t tpf;
    size_t tnext;
    size_t tlast;
    unsigned char ttype = 0x00;
    char *tname = NULL;
    char *tcontenu = NULL;
    while ( file->tc(pi) != '<' )
      pi++;
    pf = pi+1;
    while ( file->tc(pf) != '>' )
      pf++;
    tpi = pi;
    tpf = pf;
    tnext = pf+1;
    while ( ( tnext < file->size ) && ( file->tc(tnext) != '<' ) )
      tnext++;
    tlast = pi-1;
    if ( pi != 0 )
      while ( ( tlast != 0 ) && ( file->tc(tlast) != '>' ) ) {
        tlast--; }
    size_t p1 = pi+1;
    while ( file->tc(p1) == ' ' )
      p1++;
    if ( file->tc(p1) == '/' ) {
      ttype = FERMANT;
      p1++; }
    size_t p2 = p1;
    while ( ( file->tc(p2) != ' ' ) && ( file->tc(p2) != '>' ) && ( file->tc(p2) != '/' ) )
      p2++;
    p2--;
    size_t p3 = pf-1;
    while ( file->tc(p3) == ' ' )
      p3--;
    if ( file->tc(p3) == '/' )
      ttype = OUVRANT_FERMANT;
    if ( !ttype )
      ttype = OUVRANT;
    tname = extraction(am,file,p1,p2);
    if ( ttype == OUVRANT ) {
      lp[np] = sp;
      np++;
      if ( np != 1 ) {
        strcat(liste,",");
        sp++; }
      strcat(liste,tname);
      sp +=(int) strlen(tname);
      inclu = !inclusions->estPresent(liste); }
    if ( ttype == FERMANT ) {
      inclu = !inclusions->estPresent(liste);
      np--;
      sp = lp[np];
      liste[sp] = 0x00; }
    ttr[i].type = ttype;
    ttr[i].pi = tpi;
    ttr[i].pf = tpf;
    ttr[i].pnext = tnext;
    ttr[i].plast = tlast;
    ttr[i].setName(tname);
    if ( p3 > p2 ) {
      p2++;
      while ( file->tc(p2) == ' ' )
        p2++;
      if ( file->tc(p3) == '/' )
        p3--;
      while ( file->tc(p3) == ' ' )
        p3--;
      tcontenu = extraction(am,file,p2,p3);
      ttr[i].setContenu(tcontenu); }
    pi = pf+1;
    i++;
    if ( inclu ) {
      i--;
      ttr[i].contenu = NULL;
      (*nbTag)--; }
      else {
      ii++; } }
  *nbTag = ii;
  return(ttr);
}

static void tagOuvrant(char *st1,char *st2,char *tag) {
  st1[0] = '<';
  strcpy(&st1[1],tag);
  int l =(int) strlen(st1);
  st1[l] = ' ';
  st1[l+1] = 0x00;
  st2[0] = '<';
  strcpy(&st2[1],tag);
  st2[l] = '>';
  st2[l+1] = 0x00;
}

static void tagFermant(char *st1,char *st2,char *tag) {
  st1[0] = '<';
  st1[1] = '/';
  strcpy(&st1[2],tag);
  int l =(int) strlen(st1);
  st1[l] = '>';
  st1[l+1] = 0x00;
  st2[0] = '<';
  st2[1] = '/';
  strcpy(&st2[2],tag);
  st2[l] = ' ';
  st2[l+1] = 0x00;
}

static int occurence(char *s,FileLoader *file,size_t p) {
  int l =(int) strlen(s);
  for ( int i = 0 ; i < l ; i++ )
    if ( s[i] != file->tc(p+i) )
      return(0);
  return(1);
}

static size_t nextPos(char *s,FileLoader *file,size_t pos) {
  size_t p = pos;
  int l =(int) strlen(s);
  while ( ( p+l < file->size ) && !occurence(s,file,p) )
    p++;
  if ( p+l >= file->size )
    return(MOINS1);
  return(p);
}

static size_t finTagFermant(FileLoader *file,size_t pos) {
  while ( ( pos < file->size ) && ( file->tc(pos) != '>' ) )
    pos++;
  if ( pos >= file->size )
    return(MOINS1);
  return(pos);
}

static size_t trouveTag(char *tag,FileLoader *file,size_t pi,size_t *taille) {
  //printf("%10s : %d %d\n",tag,pi,*taille);
  size_t pos = pi;
  char st1[20480];
  char st2[20480];
  tagOuvrant(st1,st2,tag);
  pos = nextPos(st1,file,pos);
  if ( pos == MOINS1 )
    pos = nextPos(st2,file,pos);
  //printf("|%s|%s| %d\n",st1,st2,pos);
  if ( pos == MOINS1 )
    return(MOINS1);
  tagFermant(st1,st2,tag);
  size_t end = nextPos(st1,file,pos);
  if ( end == MOINS1 )
    end = nextPos(st2,file,pos);
  //printf("|%s|%s| %d\n",st1,st2,end);
  if ( end == MOINS1 )
    return(MOINS1);
  end = finTagFermant(file,end);
  //printf("%d %c\n",end,t[end]);
  if ( end == MOINS1 )
    return(MOINS1);
  *taille = end-pos;
  //printf("%d\n",end-pos);
  return(pos);
}

static int nombreTag(FileLoader *file,char **ts,int ns,size_t *pi,size_t *taille) {
  *pi = 0;
  *taille = file->size;
  for ( int i = 0 ; i < ns ; i++ ) {
    *pi = trouveTag(ts[i],file,*pi,taille);
    if ( *pi == MOINS1 )
      return(-1); }
  int cpt1 = 0;
  int cpt2 = 0;
  for (size_t i = *pi ; i <= *pi+*taille ; i++ ) {
    if ( file->tc(i) == '>' )
      cpt1++;
    if ( file->tc(i) == '<' )
      cpt2++; } 
  if ( cpt1 == cpt2 )
    return(cpt1);
  return(-1);
}

static TagReference *tableauReferencesTag(FileLoader *file,int *nbTag,char **ts,int ns,AllocateurMemoire *am) {
  size_t pi;
  size_t taille;
  *nbTag = nombreTag(file,ts,ns,&pi,&taille);
  if ( *nbTag == -1 )
    return(NULL);
  size_t pf = pi;
  TagReference *ttr = new TagReference[*nbTag];
  for ( int i = 0 ; i < *nbTag ; i++ ) {
    while ( file->tc(pi) != '<' )
      pi++;
    pf = pi+1;
    while ( file->tc(pf) != '>' )
      pf++;
    ttr[i].pi = pi;
    ttr[i].pf = pf;
    size_t p1 = pi+1;
    while ( file->tc(p1) == ' ' )
      p1++;
    if ( file->tc(p1) == '/' ) {
      ttr[i].type = FERMANT;
      p1++; }
    size_t p2 = p1;
    while ( ( file->tc(p2) != ' ' ) && ( file->tc(p2) != '>' ) && ( file->tc(p2) != '/' ) )
      p2++;
    p2--;
    size_t p3 = pf-1;
    while ( file->tc(p3) == ' ' )
      p3--;
    if ( file->tc(p3) == '/' )
      ttr[i].type = OUVRANT_FERMANT;
    if ( !ttr[i].type )
      ttr[i].type = OUVRANT;
    char *s = extraction(am,file,p1,p2);
    ttr[i].setName(s);
    if ( p3 > p2 ) {
      p2++;
      while ( file->tc(p2) == ' ' )
        p2++;
      if ( file->tc(p3) == '/' )
        p3--;
      while ( file->tc(p3) == ' ' )
        p3--;
      char *st = extraction(am,file,p2,p3);
      ttr[i].setContenu(st); }
    pi = pf+1; }
  return(ttr);
}

static size_t nextCararactere(char *contenu,size_t p,size_t l) {
  while ( ( p < l ) && ( contenu[p] == ' ' ) )
    p++;
  if ( p == l )
    return(MOINS1);
  return(p);
}

static size_t nextGuillemet(char *contenu,size_t p,size_t l) {
  while ( ( p < l ) && ( contenu[p] != '"' ) )
    p++;
  if ( p == l )
    return(MOINS1);
  return(p);
}

static size_t nextPostEgal(char *contenu,size_t p,size_t l) {
  while ( ( p < l ) && ( contenu[p] != '=' ) )
    p++;
  if ( p == l )
    return(MOINS1);
  p--;
  while ( contenu[p] == ' ' )
    p--;
  return(p);
}

static char *extraction(AllocateurMemoire *am,char *t,size_t pi,size_t pf) {
  char *name =(char *) am->myalloc((int) (pf-pi+2));
  for ( size_t i = 0 ; i < pf-pi+1 ; i++ )
    name[i] = t[pi+i];
  name[pf-pi+1] = 0x00;
  return(name);
}

static XMLProperty **proprietes(char *contenu,short *nb,AllocateurMemoire *am,AllocateurXMLProperty *ap,AllocateurMemoire *amtp) {
  size_t l = strlen(contenu);
  size_t p = 0;
  Array *v = new Array();
  while ( ( p < l ) && ( p != MOINS1 ) ) {
    size_t i1 = p = nextCararactere(contenu,p,l);
    if ( p != MOINS1 ) {
      size_t i2 = p = nextPostEgal(contenu,p+1,l);
      if ( p != MOINS1 ) {
        p = nextGuillemet(contenu,p+1,l);
        if ( p != MOINS1 ) {
          size_t i3 = p+1;
          p = nextGuillemet(contenu,p+1,l);
          if ( p != MOINS1 ) {
            size_t i4 = p-1;
            p++;
            XMLProperty *prpt = ap->mynew();
            char *name = extraction(am,contenu,i1,i2);
            prpt->setName(name);
            char *value = extraction(am,contenu,i3,i4);
            prpt->setValue(value);
            v->add(prpt); } } } } }
  XMLProperty **tv =(XMLProperty **) v->getArray();
  XMLProperty **ntv =(XMLProperty **) amtp->cyalloc(v->size(),sizeof(void *));
  memcpy(ntv,tv,v->size()*sizeof(void *));
  *nb =(short) v->size();
  free(tv);
  delete(v);
  return(ntv);
}

static int cptt = 0;

static char *newChaine(char *s,AllocateurMemoire *am) {
  char *dst =(char *) am->myalloc((int) strlen(s)+1);
  strcpy(dst,s);
  return(dst);
}

static int vide(char *s) {
  int i = 0;
  while ( s[i] ) {
    if ( ( s[i] != 0x20 ) && ( s[i] != 0x0D ) && ( s[i] != 0x0A ) )
      return(0);
    i++; }
  return(1);
}

static XMLTag *construction(TagReference *ttr,size_t *pos,size_t max,short *niveau,FileLoader *file,AllocateurMemoire *am,AllocateurXMLTag *at,AllocateurXMLProperty *ap,AllocateurMemoire *amtt,AllocateurMemoire *amtp,int texteInline) {
  if ( *pos >= max )
    return(NULL);
  cptt++;
  XMLTag *tg = at->mynew(newChaine(ttr[*pos].name,am));
  if ( ttr[*pos].contenu )
    tg->proprietes = proprietes(ttr[*pos].contenu,&tg->nbProprietes,am,ap,amtp);
  tg->niveau = *niveau;
  if ( ttr[*pos].type == OUVRANT ) {
    Array *vstr = new Array();
    char *s = extraction(am,file,ttr[*pos].pf+1,ttr[*pos].pnext-1);
    if ( vide(s) ) {
      am->stepBack();
      s = NULL; }
    vstr->add(s);
    (*pos)++;
    int num = 0;
    Array *v = new Array();
    while ( ttr[*pos].type != FERMANT ) {
      (*niveau)++;
      XMLTag *ftg = construction(ttr,pos,max,niveau,file,am,at,ap,amtt,amtp,texteInline);
      char *st = extraction(am,file,ttr[*pos].plast+1,ttr[*pos].pi-1);
      if ( vide(st) ) {
        am->stepBack();
        st = NULL; }
      vstr->add(st);
      ftg->num = num;
      num++;
      v->add(ftg);
      (*niveau)--; }
    tg->nbTags = v->size();
    (*pos)++;
    XMLTag **ntg =(XMLTag **) v->getArray();
    tg->tagList =(XMLTag **) amtt->cyalloc(v->size(),sizeof(void *));
    memcpy(tg->tagList,ntg,v->size()*sizeof(void *));
    free(ntg);
    if ( texteInline )
      tg->strList =(char **) vstr->getArray();
    delete(vstr);
    delete(v); }
    else
    if ( ttr[*pos].type == OUVRANT_FERMANT ) {
      (*pos)++; }
  return(tg);
}

///
/// Retour de la quantite de memoire utilisee.
///
/// @return la quantite de memoire.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 01/01/10
///
size_t XMLStructure::getUsedMemory(void) {
  return(sizeof(XMLStructure)+amtt->getUsedMemory()+amtp->getUsedMemory()+am->getUsedMemory()+at->getUsedMemory()+ap->getUsedMemory());
}

///
/// Retour du nombre de handles memoires utilises.
///
/// @return le nombre de handles memoires.
/// @author Nicolas Janey
/// @author nicolas.janey@univ-fcomte.fr
/// @version 1.0, 01/01/10
///
long XMLStructure::getUsedHandles(void) {
  return(1+amtt->getUsedHandles()+amtp->getUsedHandles()+am->getUsedHandles()+at->getUsedHandles()+ap->getUsedHandles());
}
