/****************************************************************************
                             Hyper's CD Catalog 
		A multiplatform qt and xml based catalog program
  
 Author    : Peter Deak (hyperr@freemail.hu)
 License   : GPL
 Copyright : (C) 2003 Peter Deak
****************************************************************************/

#include <stdio.h>
#include <ctype.h>

#include <expat.h>
#include <zlib.h>
#include <qstring.h>

#include "wdbfile.h"
#include "adddialog.h"
#include "recode.h"
#include "dbase.h"
#include "cdcat.h"

//#define XML_ENCODING   "UTF-8"
#define XML_ENCODING   "ISO-8859-1"
#define BUFFSIZE	8192

char *out1=NULL;
char *out2=NULL;
char *out3=NULL;
char *out4=NULL;
char *out5=NULL;

char encodeHex[] = "0123456789ABCDEF";
/*************************************************************************/

int getTypeFS(const char *str)
 {
  if(str == NULL) return -1;
  if(!strcmp("CD"          ,str)) return CD;  
  if(!strcmp("DVD"         ,str)) return DVD;
  if(!strcmp("HardDisc"    ,str)) return HARDDISC; 
  if(!strcmp("floppy"      ,str)) return FLOPPY;
  if(!strcmp("NetworkPlace",str)) return NETPLACE;  
  if(!strcmp("flashdrive"  ,str)) return FLASHDRV;
  if(!strcmp("other"       ,str)) return OTHERD;   
  return UNKNOWN;   
 }

const char *getMType(int t)
{
 switch(t)
  {
   case UNKNOWN : return "unknown";
   case CD      : return "CD";
   case DVD     : return "DVD";
   case HARDDISC: return "HardDisc";
   case FLOPPY  : return "floppy";
   case NETPLACE: return "NetworkPlace";
   case FLASHDRV: return "flashdrive";
   case OTHERD  : return "other";
  }
 return NULL;  
}

float getSizeFS(const char *str)
 {
  float  r=0;
  char   s[10];
  
  strcpy(s,"");
  if(str == NULL) return -1; 
  if(sscanf(str,"%f %s",&r,s) != 2)
     return -1;
  return r;
 }
 
int   getSizetFS(const char *str)
 {
  float  r;
  char   s[10];
  
  if(str == NULL) return -1; 
  if(sscanf(str,"%f %s",&r,s) != 2) 
     return -1;
     
  if(!strcmp(s,"byte")) return BYTE;
  if(!strcmp(s,"Kb")) return KBYTE;
  if(!strcmp(s,"Mb")) return MBYTE;
  if(!strcmp(s,"Gb")) return GBYTE;
  return -1;
 }

const char *getSType(int t)
{
 switch(t)
  {
   case BYTE : return " byte";
   case KBYTE: return " Kb";
   case MBYTE: return " Mb";
   case GBYTE: return " Gb";
  }
 return NULL; 
}

/*****************************************************************************
 WRITING FILE:
*****************************************************************************/
char span[256];
const char *FileWriter::spg(int spn)
 {
  int  i;
  
  if(!nicef) return "";

  for(i=0;i<254 && i<(spn*2);i++) 
     span[i]=' ';
  span[i]='\0';
  return span;
 }

FileWriter::FileWriter(gzFile ff,bool nicefp)
 {
  nicef = nicefp;
  level = 0;
  f = ff;
 }


void FileWriter::commentWriter(char *c)
 {
  if(c == NULL) 
       return;
  level++;       
  gzprintf(f,"%s<comment>",spg(level));
  gzprintf(f,"%s",recode(c,&out1));
  gzprintf(f,"%s</comment>\n",spg(level));
  level--;
 }

int  FileWriter::writeDown(Node *source)
 {
  int i=0;
  switch(source->type)
   {
    case HC_UNINITIALIZED: return 1;
    
    case HC_CATALOG:       writeHeader(); 
                           i=writeCatalog(source);
                           break;
    case HC_MEDIA:         i=writeMedia(source);    
                           break;
    case HC_DIRECTORY:     i=writeDirectory(source);    
                           break;
    case HC_FILE:          i=writeFile(source);    
                           break;
    case HC_MP3TAG:        i=writeMp3Tag(source);    
                           break;
    case HC_CONTENT:       i=writeContent(source);    
                           break;
    case HC_CATLNK:        i=writeCatLnk(source);    
                           break;

   }  
   return i;
  }

int  FileWriter::writeHeader(void)
 {
  level = 0;
  progress(pww);
  gzprintf(f,"<?xml version=\"1.0\" encoding=\"%s\"?>",XML_ENCODING);
  gzprintf(f,"\n<!DOCTYPE HyperCDCatalogFile>\n\n");
  gzprintf(f,"\n<!-- CD Catalog Database file, generated by CdCat ");
  gzprintf(f,"\n     Homepage: %s  Author: Pe'ter Dea'k  hyperr@freemail.hu)",HOMEPAGE);
  gzprintf(f,"\n     Program-Version: %s  -->\n\n",VERSION,DVERS);
  return 0;
 }
 
int  FileWriter::writeCatalog(Node *source)
 {
  progress(pww);
  gzprintf(f,"<catalog name=\"%s\" owner=\"%s\" time=\"%s\">\n",
            recode(((DBCatalog *)(source->data))->name,&out1),
	    recode(((DBCatalog *)(source->data))->owner,&out2),
	    recode(((DBCatalog *)(source->data))->modification,&out3) );

  gzprintf(f,"<datafile version=\"%s\"/>\n",
              DVERS);

  commentWriter(((DBCatalog *)(source->data))->comment);
  level++;
  if(source->child != NULL) writeDown(source->child);
  level--;
  gzprintf(f,"</catalog>\n");      	    
  if(source->next  != NULL) writeDown(source->next);

  return 0;
 }
 
int  FileWriter::writeMedia(Node *source)
 {
  progress(pww);
  gzprintf(f,"%s<media name=\"%s\" number=\"%d\" owner=\"%s\" type=\"%s\" time=\"%s\">\n",
            spg(level),
            recode(((DBMedia *)(source->data))->name,&out1),
	    ((DBMedia *)(source->data))->number,
	    recode(((DBMedia *)(source->data))->owner,&out2),
	    getMType(((DBMedia *)(source->data))->type),
	    recode(((DBMedia *)(source->data))->modification,&out3));
  
  commentWriter(((DBMedia *)(source->data))->comment);
  
  //write borrowing info if exists
  if(((DBMedia *)(source->data))->borrowing != NULL)
     gzprintf(f,"%s<borrow>%s</borrow>\n",
               spg(level),
               recode(((DBMedia *)(source->data))->borrowing,&out1));
  
  level++;
  if(source->child != NULL) writeDown(source->child);
  level--;
  gzprintf(f,"%s</media>\n",spg(level));      	    
  if(source->next  != NULL) writeDown(source->next);

  return 0;
 }
 
int  FileWriter::writeDirectory(Node *source)
 {
  progress(pww);
  gzprintf(f,"%s<directory name=\"%s\" time=\"%s\">\n",
            spg(level),
            recode(((DBDirectory *)(source->data))->name,&out1),
	    recode(((DBDirectory *)(source->data))->modification,&out3));
  
  commentWriter(((DBDirectory *)(source->data))->comment);
 
  level++;
  if(source->child != NULL) writeDown(source->child);
  level--;
  gzprintf(f,"%s</directory>\n",spg(level));      	    
  if(source->next  != NULL) writeDown(source->next);

  return 0; 
 }
 
int  FileWriter::writeFile(Node *source)
 {
  gzprintf(f,"%s<file name=\"%s\" size=\"%.2f%s\" time=\"%s\">\n",
            spg(level),
            recode(((DBFile *)(source->data))->name,&out1),
	    ((DBFile *)(source->data))->size,
	    getSType((((DBFile *)(source->data))->sizeType)),
	    recode(((DBFile *)(source->data))->modification,&out3));
  commentWriter(((DBFile *)(source->data))->comment);
  level++;
  if(source->child != NULL) 
           writeDown(source->child);
  if(((DBFile *)(source->data))->prop != NULL) 
           writeDown(((DBFile *)(source->data))->prop);
  level--;
  gzprintf(f,"%s</file>\n",spg(level));      	    
  if(source->next  != NULL) writeDown(source->next);
  return 0; 
 }

int  FileWriter::writeMp3Tag(Node *source)
 {
  gzprintf(f,"%s<mp3tag artist=\"%s\" title=\"%s\" album=\"%s\"  year=\"%s\">",
            spg(level),
            recode(((DBMp3Tag *)(source->data))->artist,&out1),
            recode(((DBMp3Tag *)(source->data))->title,&out2),
            recode(((DBMp3Tag *)(source->data))->album,&out3),
            recode(((DBMp3Tag *)(source->data))->year,&out4));
  gzprintf(f,"%s",recode(((DBMp3Tag *)(source->data))->comment,&out5));      	    
  gzprintf(f,"%s</mp3tag>\n",spg(level));      	    
  if(source->next  != NULL) writeDown(source->next);
  return 0;
 }

int  FileWriter::writeContent(Node *source)
 {
  unsigned long i;
  unsigned char c;
  gzprintf(f,"%s<content>",spg(level));

  for(i=0;i<((DBContent *)(source->data))->storedSize;i++)
   {
    c =((DBContent *)(source->data))->bytes[i];
    gzputc(f,encodeHex[(c & 0xF0 )>>4]);
    gzputc(f,encodeHex[ c & 0x0F     ]);
   }
  gzprintf(f,"%s</content>\n",spg(level));      	    
  if(source->next  != NULL) writeDown(source->next);
  return 0;
 }

int  FileWriter::writeCatLnk(Node *source)
 {
  progress(pww);
  gzprintf(f,"%s<catlnk name=\"%s\" location=\"%s\" >\n",
            spg(level),
            (recode(((DBCatLnk *)(source->data))->name,&out1)) + 1, //to remove the leading @
	    recode(((DBCatLnk *)(source->data))->location,&out3));
  
  commentWriter(((DBCatLnk *)(source->data))->comment);
  gzprintf(f,"%s</catlnk>\n",spg(level));      	    
 
  if(source->next  != NULL) writeDown(source->next);
  return 0; 
 }

/*****************************************************************************
 READING FILE:
*****************************************************************************/
int clearbuffer = 1;
unsigned long buffpos=0;
XML_Parser *pp = NULL;

unsigned char decodeHexa(char a,char b) //try to decode a hexadecimal byte to char very fast
 {                                      //possible values a,b: "0123456789ABCDEF"  !!!
  unsigned char r=0;       
     
  if(a>='A') r =  ((a-'A')+10);
  else       r =  ( a-'0'    );
  r <<= 4;
  if(b>='A') r += ((b-'A')+10);
  else       r += ( b-'0'    );
   
  return r;
 }

float FileReader::getFloat(const char **from,char *what,char *err)
 {
   float r;
   int i;

   if(from == NULL)
    {
     errormsg = QString("Line %1: %2").arg(XML_GetCurrentLineNumber(*pp)).arg(err);
     error = 1;
     return 0;
    }
   for(i=0;;i+=2)
    {
        if(from[i] == NULL)
          {
	    errormsg = QString("Line %1: %2,I can't find \"%3\" attribute")
	                     .arg(XML_GetCurrentLineNumber(*pp)).arg(err).arg(what);  
            error  = 1;
	    return   0;
          }
        if(!strcmp(from[i],what))
          {
            if(from[i+1] == NULL)
              {
	       errormsg = QString("Line %1: %2").arg(XML_GetCurrentLineNumber(*pp)).arg(err);
               error  = 1;	       
	       return 0;
              }
            if(1 != sscanf(from[i+1],"%f",& r))
              {
	        errormsg = QString("Line %1: %2:I can't understanding \"%3\" attribute.")
		            .arg(XML_GetCurrentLineNumber(*pp)).arg(err).arg(what);  
                error  = 1;
                return   0;
             }
            return r;
          }
    }
  return 0;
 }

char * FileReader::getStr(const char **from,char *what,char *err)
 {
   int i;

   if(from == NULL)
    {
     errormsg = QString("Line %1: %2").arg(XML_GetCurrentLineNumber(*pp)).arg(err);
     error=1;
     return NULL;
    }
   for(i=0;;i+=2)
    {
        if(from[i] == NULL)
          {
	    errormsg = QString("Line %1: %2:I can't find \"%3\" attribute.")
	                 .arg(XML_GetCurrentLineNumber(*pp)).arg(err).arg(what);  
            error  = 1;
	    return   NULL;
          }
        if(!strcmp(from[i],what))
          {
            if(from[i+1] == NULL)
              {
	       errormsg = QString("Line %1: %2").arg(XML_GetCurrentLineNumber(*pp)).arg(err);
               error = 1;
               return NULL;
              }
	    return ((char *)(from[i+1]));  
          }
    }
  return NULL;
 }
 
int FileReader::isthere(const char **from,char *what)
 {
   int i;

   if(from == NULL)
     return 0;
   for(i=0;;i+=2)
    {
        if(from[i] == NULL)
          return 0;
        if(!strcmp(from[i],what))
          return 1;
    }
  return 0;
 }

#define FREA ((FileReader *)(data))

DBMp3Tag *tmp_tagp=NULL;

static void start(void *data, const char *el, const char **attr) 
 {
  char *tc1,*tc2,*tc3,*tc4,*tc5;
  float tf1;
  int   ti1;
  
  if(FREA->error) return; 
  /*That case I found an error in file -> needs exit the pasing as fast as I can.*/
  
  clearbuffer = 1;
  if(!strcmp(el,"catalog"))
   {
    if(FREA->insert) return;
    
    ((DBCatalog *)((FREA->sp)->data)) ->name = 
         mstr(FREA->getStr(attr,"name","Error while parsing \"catalog\" node")); 
    if(FREA->error) return;	 

    ((DBCatalog *)((FREA->sp)->data)) ->owner= 
         mstr(FREA->getStr(attr,"owner","Error while parsing \"catalog\" node")); 
    if(FREA->error) return;	 	 

    tc1 = FREA->getStr(attr,"time","Error while parsing \"catalog\" node");
    if(FREA->error) return;	 	 
    
    strcpy(((DBCatalog *)((FREA->sp)->data)) ->modification,tc1); 
   }

  if(!strcmp(el,"datafile"))
   {
    Node *tmp=FREA->sp;
    if(FREA->insert) return;
    
    while(tmp->type != HC_CATALOG) tmp=tmp->parent;
    
    ((DBCatalog *)(tmp->data)) ->fileversion = 
         mstr(FREA->getStr(attr,"version","Error while parsing \"datafile\" node")); 
    if(FREA->error) return;	 
   }

 if(!strcmp(el,"media"))
   {
    Node *tt = FREA->sp->child;
    
    if(tt == NULL) FREA->sp->child = tt = new Node(HC_MEDIA,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_MEDIA,FREA->sp);
      tt=tt->next; 
     }    
     
    if(FREA->insert)
     {
       int i,newnum,ser=0;
       Node *ch = tt->parent->child;
       char newname[512];
       
       
       tc1 = FREA->getStr  (attr,"name"  ,"Error while parsing \"media\" node");
       if(FREA->error) return;	 	        
       if(tc1[0] == '@')
        {
	  FREA->errormsg = QString(
"Line %1: The media name begin with \"@\".\n\
It is disallowed since cdcat version 0.98 !\n\
Please change it with an older version or rewrite it in the xml file!")
	                    .arg(XML_GetCurrentLineNumber(*pp));
			    
	  FREA->error = 1;
	  return;
	} 
       
       strcpy(newname,tc1);
       
       newnum = (int)FREA->getFloat (attr,"number","Error while parsing \"media\" node");
       if(FREA->error) return;	 	        

       /*make the number unique*/           
       for(i=1;i==1;)
        {
	 i=0;
         for(ch = tt->parent->child;ch != NULL; ch = ch->next)
          {
	   if(ch->data != NULL)
	     if(((DBMedia *)(ch->data))->number ==  newnum )
	       i=1; 
	  }
	 if(i) newnum++; 
	}  

       /*make the name unique*/           
       for(i=1;i==1;)
        {
	 i=0;
         for(ch = tt->parent->child;ch != NULL; ch = ch->next)
          {
	   if(ch->data != NULL)
	     if(strcmp(((DBMedia *)(ch->data))->name ,  newname)==0)
	       i=1; 
	  }
	 if(i) 
	  { 
	    char tmp[512];
	    ser++;
	    strcpy(tmp,newname);
	    sprintf(newname,"%s#%d",tmp,ser);
	  } 
	}  

	
        /*Fill data part:*/
	tc2 = mstr(FREA->getStr  (attr,"owner" ,"Error while parsing \"media\" node"));
	tc3 = FREA->getStr  (attr,"type"  ,"Error while parsing \"media\" node");
	tc4 = FREA->getStr  (attr,"time"  ,"Error while parsing \"media\" node");
	if(FREA->error) return;
	ti1 = getTypeFS(tc3);
	if(ti1 == UNKNOWN)
	 {
	  FREA->errormsg = QString("Line %1: Unknown media type in the file. (\"%2\")")
	                    .arg(XML_GetCurrentLineNumber(*pp)).arg((const char *)tc3);
	  FREA->error = 1;
	  return;
	 }
	
        tt->data = (void *) new DBMedia(
                mstr(newname),newnum,tc2,ti1,NULL,tc4);
     	
     } 
    else
     {
      /*Fill data part:*/
      tc2 = mstr(FREA->getStr  (attr,"name"  ,"Error while parsing \"media\" node"));
      tf1 = FREA->getFloat(attr,"number","Error while parsing \"media\" node");
      tc3 = mstr(FREA->getStr  (attr,"owner" ,"Error while parsing \"media\" node"));
      tc4 = FREA->getStr  (attr,"type"  ,"Error while parsing \"media\" node");
      tc5 = FREA->getStr  (attr,"time"  ,"Error while parsing \"media\" node");
      if(FREA->error) return;
      
      if(tc2[0] == '@')
        {
	  FREA->errormsg = QString(
"Line %1: The media name begin with \"@\".\n\
It is disallowed since cdcat version 0.98 !\n\
Please change it with an older version or rewrite it in the xml file!")
	                    .arg(XML_GetCurrentLineNumber(*pp));
	  FREA->error = 1;
	  return;
	} 
      
      ti1 = getTypeFS(tc4);
      if(ti1 == UNKNOWN)
	 {
	  FREA->errormsg = QString("Line %1: Unknown media type in the file. (\"%2\")")
	                  .arg(XML_GetCurrentLineNumber(*pp)).arg(tc4);
	  FREA->error = 1;
	  return;
	 }
      
      tt->data = (void *) new DBMedia(tc2,(int)tf1,tc3,ti1,NULL,tc5);
     }
    /*Make this node to the actual node:*/
    FREA->sp = tt;
   }
 if(!strcmp(el,"directory"))
   {
    Node *tt = FREA->sp->child;
    
    if(tt == NULL) FREA->sp->child = tt = new Node(HC_DIRECTORY,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_DIRECTORY,FREA->sp);
      tt=tt->next; 
     }    
    /*Fill data part:*/
    tc1 = mstr(FREA->getStr  (attr,"name"  ,"Error while parsing \"directory\" node"));
    tc2 = FREA->getStr  (attr,"time" ,"Error while parsing \"directory\" node");
    if(FREA->error) return;
    tt->data = (void *) new DBDirectory(tc1,tc2,NULL);
    
    /*Make this node to the actual node:*/
    FREA->sp = tt;   
   }
 if(!strcmp(el,"file"))
   {
   
    Node *tt = FREA->sp->child;
    
    if(tt == NULL) FREA->sp->child = tt = new Node(HC_FILE,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_FILE,FREA->sp);
      tt=tt->next; 
     }    
    /*Fill data part:*/
    
    tc1 = mstr(FREA->getStr  (attr,"name"  ,"Error while parsing \"file\" node"));
    tc2 = FREA->getStr  (attr,"time"  ,"Error while parsing \"file\" node");
    tc3 = FREA->getStr(attr,"size","Error while parsing \"file\" node");
    tc4 = FREA->getStr(attr,"size","Error while parsing \"file\" node");
    if(FREA->error) return;

    tf1 = getSizeFS(tc3);
    if(tf1 == -1)
	 {
	  FREA->errormsg = QString("Line %1: Unknown size data in file node. (\"%2\")")
	                   .arg(XML_GetCurrentLineNumber(*pp)).arg(tc3);
	  FREA->error = 1;
	  return;
	 }
    
    ti1 = getSizetFS(tc4);
    if(ti1 == -1)
	 {
	  FREA->errormsg = QString("Line %1: Unknown size type in file node. (\"%2\")")
	                   .arg(XML_GetCurrentLineNumber(*pp)).arg(tc4);
	  FREA->error = 1;
	  return;
	 }

    
    tt->data = (void *) new DBFile(tc1,tc2,NULL,tf1,ti1);
    
    /*Make this node to the actual node:*/
    FREA->sp = tt;   
   
   }
 if(!strcmp(el,"mp3tag"))
   {
    Node *tt =  ((DBFile *)(FREA->sp->data))->prop;
    if(tt == NULL) ((DBFile *)(FREA->sp->data))->prop = tt = new Node(HC_MP3TAG,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_MP3TAG,FREA->sp);
      tt=tt->next; 
     }    
    /*Fill data part:*/
    tc1 = FREA->getStr(attr,"artist"  ,"Error while parsing \"mp3tag\" node");
    tc2 = FREA->getStr(attr,"title"   ,"Error while parsing \"mp3tag\" node");
    tc3 = FREA->getStr(attr,"album"  ,"Error while parsing \"mp3tag\" node");
    tc4 = FREA->getStr(attr,"year"   ,"Error while parsing \"mp3tag\" node");
    if(FREA->error) return;

    tmp_tagp = new DBMp3Tag(tc1,tc2,"no comment",tc3,tc4);
	
    tt->data = (void *)tmp_tagp;		
    /*I don't make this node to the actual node because this won't be parent.*/
   }

 if(!strcmp(el,"catlnk"))
   {
    char *memname;
    Node *tt = FREA->sp->child;
    
    if(tt == NULL) FREA->sp->child = tt = new Node(HC_CATLNK,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_CATLNK,FREA->sp);
      tt=tt->next; 
     }    
    /*Fill data part:*/
    tc1 = mstr(FREA->getStr (attr,"name"  ,"Error while parsing \"catlnk\" node"));
    tc2 = mstr(FREA->getStr (attr,"location" ,"Error while parsing \"catlnk\" node"));
    if(FREA->error) return;
    
    memname = new char[strlen(tc1) + 2];
    sprintf(memname,"@%s",tc1);
    delete [] tc1;
    
    tt->data = (void *) new DBCatLnk(memname,tc2,NULL);
    
    /*Make this node to the actual node:*/
    FREA->sp = tt;   
   }

 if(!strcmp(el,"content"))
   {
    /*nothing*/
   }

 if(!strcmp(el,"comment"))
   {
    /*nothing*/
   }
 if(!strcmp(el,"borrow"))
   {
    /*nothing*/
   }

 }  
/*********************************************************************/
static void end(void *data, const char *el) 
 {
  if(FREA->error) return; 
  /*That case I found an error in file -> needs exit the pasing as fast as I can.*/

  if(!strcmp(el,"catalog"))
   {
    //End parsing ! 
   }

  if(!strcmp(el,"datafile"))
   {
    //End parsing ! 
   }

 if(!strcmp(el,"media"))
   {
    /*Restore the parent node tho the actual node:*/
    FREA->sp = FREA->sp->parent;     
   }
 if(!strcmp(el,"directory"))
   {
    /*Restore the parent node tho the actual node:*/
    FREA->sp = FREA->sp->parent;     
   }
 if(!strcmp(el,"file"))
   {
    /*Restore the parent node tho the actual node:*/
    FREA->sp = FREA->sp->parent;     
   }
 if(!strcmp(el,"mp3tag"))
   {
    //strcpy(tmp_tagp->comment,FREA->dataBuffer);		
    if(tmp_tagp->comment != NULL)
      delete [] tmp_tagp->comment;
      tmp_tagp->comment = mstr(FREA->dataBuffer);		
    tmp_tagp = NULL;
   }
 if(!strcmp(el,"catlnk"))
   {
    /*Restore the parent node tho the actual node:*/
    FREA->sp = FREA->sp->parent;     
   }

 if(!strcmp(el,"content"))
  {
    unsigned char *bytes;
    unsigned long rsize,i;
    
    Node *tt =  ((DBFile *)(FREA->sp->data))->prop;
    if(tt == NULL)
       ((DBFile *)(FREA->sp->data))->prop = tt = new Node(HC_CONTENT,FREA->sp);
    else
     {
      while(tt->next != NULL) tt = tt->next;
      tt->next =  new Node(HC_CONTENT,FREA->sp);
      tt=tt->next; 
     }    
    /*Fill data part:*/
    bytes = new unsigned char[(rsize=(strlen(FREA->dataBuffer)/2)) + 1];
    for(i=0;i<rsize;i++)
        bytes[i] = decodeHexa(FREA->dataBuffer[i*2],FREA->dataBuffer[i*2 + 1]);
    bytes[rsize] = '\0';
    tt->data = (void *) new DBContent(bytes,rsize);
  }

 if(!strcmp(el,"comment"))
   {
   switch(FREA->sp->type)
     {
      case HC_CATALOG  : 

          ((DBCatalog    *)(FREA->sp->data)) -> comment = mstr(FREA->dataBuffer);
         break;
      case HC_MEDIA    : 
          ((DBMedia      *)(FREA->sp->data)) -> comment = mstr(FREA->dataBuffer);
         break;
      case HC_DIRECTORY: 
          ((DBDirectory *)(FREA->sp->data)) -> comment = mstr(FREA->dataBuffer);
         break;
      case HC_FILE     : 
          ((DBFile      *)(FREA->sp->data)) -> comment = mstr(FREA->dataBuffer);
         break;
      case HC_CATLNK   : 
          ((DBCatLnk    *)(FREA->sp->data)) -> comment = mstr(FREA->dataBuffer);
         break;
      case HC_MP3TAG:
	  FREA->errormsg = QString("Line %1: It isnt allowed comment node in mp3tag node.")
	                           .arg(XML_GetCurrentLineNumber(*pp));
          FREA->error = 1;
         break;	 
      	 
     }
   }
   
 if(!strcmp(el,"borrow"))
   {
   switch(FREA->sp->type)
     {
      case HC_CATALOG  : 
      case HC_DIRECTORY: 
      case HC_FILE     : 
      case HC_MP3TAG   :      
      case HC_CATLNK   :            
	  FREA->errormsg = QString("Line %1: The borrow node only allowed in media node.")
	                           .arg(XML_GetCurrentLineNumber(*pp));
          FREA->error = 1;
         break;
      case HC_MEDIA    : 
          ((DBMedia      *)(FREA->sp->data)) -> borrowing = mstr(FREA->dataBuffer);
         break;

     }
   }
 
   clearbuffer = 1; 
 }

void getCharDataFromXML(void *data,const char *s,int len)
 {
  int copylen=len;

  if(FREA->error) return; 
  /*That case I found an error in file -> needs exit the pasing as fast as I can.*/

  if(clearbuffer)
   {
    buffpos = 0;
    clearbuffer = 0;
   }    
 
  if(buffpos + len >= (MAX_STORED_SIZE*2))
     copylen = (MAX_STORED_SIZE*2) - buffpos;

  memcpy((FREA->dataBuffer)+buffpos,s,sizeof(char) * copylen );
  buffpos += copylen; 
  FREA->dataBuffer[buffpos] = '\0';       
 }
 

int FileReader::readFrom(Node *source) 
 {
  char *Buff = new char[BUFFSIZE];
  XML_Parser p = XML_ParserCreate(NULL);
  pp = &p;
 
  error = 0;
  sp    = source;

                
  dataBuffer = new char[(MAX_STORED_SIZE*2)+64];
  //I allocated MAX_STORED_SIZE*2 becouse the hexadecimal data is twice
  //  as long than the normal data
  //WARNING: big data segment 256 kByte !!!
  
  if (p == NULL)
   {
    errormsg = QString("Couldn't allocate memory for parser");
    delete [] Buff;
    delete [] dataBuffer;
    return 1;
   }

  XML_SetUserData(p,this);
  XML_SetElementHandler(p, start, end);
  XML_SetCharacterDataHandler(p,getCharDataFromXML);
  for (;;) 
  {
    int done;
    int len;

    progress(pww);
    
    len = gzread(f,Buff,BUFFSIZE);
   if (len == -1)
     {
      errormsg = QString("Read error");
      delete [] Buff;
      delete [] dataBuffer;
      return 1;
     }

    done = gzeof(f);

    if (! XML_Parse(p, Buff, len, done)) 
     {
      errormsg = QString("Parse error at line %1:\n%2\n")
                     .arg(XML_GetCurrentLineNumber(p))
		     .arg(XML_ErrorString(XML_GetErrorCode(p)));
      
      delete [] Buff;
      delete [] dataBuffer;
      return 1;
     }

    if(done || error)
     {
      delete [] Buff;
      delete [] dataBuffer;
      return error;
     }
  }
}

/* ********************************************************************* */
char *catname;

static void gn_start(void *data, const char *el, const char **attr) 
 {
  if(!strcmp(el,"catalog"))
   {
    catname = mstr(FREA->getStr(attr,"name","Error while parsing \"catalog\" node")); 
   }
 }  

static void gn_end(void *data, const char *el) 
 {
 }

char * FileReader::getCatName(void)
 {
  catname = NULL;
  char *Buff = new char[BUFFSIZE];
  XML_Parser p = XML_ParserCreate(NULL);
                
  if (p == NULL)
   {
    delete [] Buff;
    return NULL;
   }

  XML_SetUserData(p,this);
  XML_SetElementHandler(p, gn_start, gn_end);
  for (;;) 
  {
    int done;
    int len;

    len = gzread(f,Buff,BUFFSIZE);
    if (len == -1)
     {
      delete [] Buff;
      return NULL;
     }

    done = gzeof(f);
    if (! XML_Parse(p, Buff, len, done)) 
     {
      delete [] Buff;
      return NULL;
     }

    if(done || catname != NULL)
     {
      delete [] Buff;
      return mstr(catname);
     } 
  }
 }


  

