/**************************************************************************** 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 #include #include #include #include #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",spg(level)); gzprintf(f,"%s",recode(c,&out1)); gzprintf(f,"%s\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_ENCODING); gzprintf(f,"\n\n\n"); gzprintf(f,"\n\n\n",VERSION,DVERS); return 0; } int FileWriter::writeCatalog(Node *source) { progress(pww); gzprintf(f,"\n", recode(((DBCatalog *)(source->data))->name,&out1), recode(((DBCatalog *)(source->data))->owner,&out2), recode(((DBCatalog *)(source->data))->modification,&out3) ); gzprintf(f,"\n", DVERS); commentWriter(((DBCatalog *)(source->data))->comment); level++; if(source->child != NULL) writeDown(source->child); level--; gzprintf(f,"\n"); if(source->next != NULL) writeDown(source->next); return 0; } int FileWriter::writeMedia(Node *source) { progress(pww); gzprintf(f,"%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%s\n", spg(level), recode(((DBMedia *)(source->data))->borrowing,&out1)); level++; if(source->child != NULL) writeDown(source->child); level--; gzprintf(f,"%s\n",spg(level)); if(source->next != NULL) writeDown(source->next); return 0; } int FileWriter::writeDirectory(Node *source) { progress(pww); gzprintf(f,"%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\n",spg(level)); if(source->next != NULL) writeDown(source->next); return 0; } int FileWriter::writeFile(Node *source) { gzprintf(f,"%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\n",spg(level)); if(source->next != NULL) writeDown(source->next); return 0; } int FileWriter::writeMp3Tag(Node *source) { gzprintf(f,"%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\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",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\n",spg(level)); if(source->next != NULL) writeDown(source->next); return 0; } int FileWriter::writeCatLnk(Node *source) { progress(pww); gzprintf(f,"%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\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;idataBuffer[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); } } }