Página principal | Lista alfabética | Lista de componentes | Lista de archivos | Miembros de las clases | Archivos de los miembros | Páginas relacionadas

Archivero.cpp

Ir a la documentación de este archivo.
00001 
00006 /*
00007    MUnDoCAAD MUD Engine
00008    Copyright (C) 2002-2005 José Manuel Ferrer Ortiz
00009 
00010    *****************************************************************************
00011    *                                                                           *
00012    *  This program is free software; you can redistribute it and/or modify it  *
00013    *  under the terms of the GNU General Public License version 2, as          *
00014    *  published by the Free Software Foundation.                               *
00015    *                                                                           *
00016    *  This program is distributed in the hope that it will be useful, but      *
00017    *  WITHOUT ANY WARRANTY; without even the implied warranty of               *
00018    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU         *
00019    *  General Public License version 2 for more details.                       *
00020    *                                                                           *
00021    *  You should have received a copy of the GNU General Public License        *
00022    *  version 2 along with this program; if not, write to the Free Software    *
00023    *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA  *
00024    *                                                                           *
00025    *****************************************************************************
00026 */
00027 
00028 
00029 #include <QDir>
00030 
00031 #include "Archivero.hpp"
00032 
00033 
00034 extern QDir dir_datos;
00035 
00036 
00038 Archivero::Archivero () : ccache (TAM_CCACHE * 1024), rcache (TAM_RCACHE * 1024)
00039 {
00040 }
00041 
00043 Archivero::~Archivero ()
00044 {
00045   qDebug ("Destructor de Archivero");
00046 }
00047 
00064 QString Archivero::BuscaPropiedad (const QString &nom_ent,
00065                                    const QString &nom_prop)
00066 {
00067   QStringList lista_ents;  // Lista de entidades en las que buscar
00068 
00069   QDomDocument documento ("entidad");
00070   QDomNode     nodo;
00071   QDomElement  elemento;
00072   QDomAttr     atributo;
00073 
00074   // Añadimos a la lista la entidad a la que pertenece la propiedad
00075   lista_ents += nom_ent;
00076 
00077   for (QStringList::Iterator iter = lista_ents.begin();
00078        iter != lista_ents.end(); ++iter)
00079   {
00080     if (!CargaDocumento (documento, *iter))
00081       return (QString::null);
00082 
00083     // Recorremos el árbol DOM para añadir las herencias a la lista y mirar
00084     // si la propiedad está en esta entidad
00085     elemento = documento.documentElement();
00086     nodo     = elemento.firstChild();
00087     while (!nodo.isNull())
00088     {
00089       elemento = nodo.toElement();
00090       if (!elemento.isNull())
00091       {
00092         if (elemento.tagName() != "herencia")  // El elemento es una propiedad
00093         {
00094           atributo = elemento.attributeNode ("nombre");
00095           // Comparamos el nombre sin distinguir mayúsculas de minúsculas
00096           if ((atributo.value().length() == nom_prop.length()) &&
00097               (atributo.value().startsWith (nom_prop, Qt::CaseInsensitive)))
00098           {
00099             // Hemos encontrado la propiedad
00100             return (*iter);
00101           }
00102         }
00103         else  // El elemento es una herencia
00104         {
00105           atributo = elemento.attributeNode ("entidad");
00106 
00107           // Comprobamos si ya estaba en la lista, sin distinguir mayúsculas de
00108           // minúsculas
00109           if (!lista_ents.contains (atributo.value(),
00110                                     Qt::CaseInsensitive))  // No estaba ya
00111             lista_ents += atributo.value();  // Pues la añadimos
00112         }
00113       }
00114       nodo = nodo.nextSibling();
00115     }
00116   }
00117 
00118   // No hemos encontrado la propiedad
00119   qWarning ("La entidad \"%s\" no dispone de la propiedad \"%s\"",
00120             nom_ent.toLatin1().constData(), nom_prop.toLatin1().constData());
00121 
00122   return (QString::null);
00123 }
00124 
00126 
00134 bool Archivero::CargaDocumento (QDomDocument &documento, const QString &nom_ent)
00135 {
00136   // Buscamos, sin distinguir mayúsculas/minúsculas, el nombre de fichero de la
00137   // entidad
00138   QStringList lista (dir_datos.entryList (QDir::Files).filter (nom_ent + ".xml",
00139                      Qt::CaseInsensitive));
00140 
00141   QStringList::iterator iter (lista.begin());
00142 
00143   for ( ; iter != lista.end(); ++iter)
00144     if ((*iter).length() == (nom_ent.length() + 4))  // 4 es la longitud de la
00145                                                      // extensión ".xml"
00146       break;  // Hemos encontrado el nombre de fichero de la entidad
00147 
00148   if (iter == lista.end())  // No encontrado
00149   {
00150     qWarning ("No se ha encontrado el fichero \"%s\"", dir_datos.filePath
00151               (nom_ent + ".xml").toLatin1().constData());
00152     return (false);
00153   }
00154 
00155   QFile fichero (dir_datos.filePath (*iter));
00156 
00157   if (!fichero.open (QIODevice::ReadOnly | QIODevice::Text))
00158   {
00159     // No se ha podido abrir el archivo
00160     qWarning ("\"%s\": %s", fichero.fileName().toLatin1().constData(),
00161               fichero.errorString().toLatin1().constData());
00162     return (false);
00163   }
00164 
00165   QString dsc_error;  // Descripción del error
00166   int     lin_error, col_error;  // Línea y columna del error, respectivamente
00167 
00168   if (!documento.setContent (&fichero, &dsc_error, &lin_error, &col_error))
00169   {
00170     fichero.close();
00171 
00172     qWarning ("\"%s\" (%d, %d): %s", fichero.fileName().toLatin1().constData(),
00173               lin_error, col_error, dsc_error.toLatin1().constData());
00174 
00175     return (false);
00176   }
00177 
00178   fichero.close();
00179   return (true);
00180 }
00181 
00183 
00192 unsigned char Archivero::DaModoPropiedad (const QString &nom_ent,
00193                                           const QString &nom_prop)
00194 {
00195   const Propiedad *prop = ObtenPropiedad (nom_ent, nom_prop);
00196 
00197   if (prop != NULL)
00198     return (prop->modo);
00199   else
00200     return ((unsigned char) -1);
00201 }
00202 
00204 
00213 unsigned char Archivero::DaTipoPropiedad (const QString &nom_ent,
00214                                           const QString &nom_prop)
00215 {
00216   const Propiedad *prop = ObtenPropiedad (nom_ent, nom_prop);
00217 
00218   if (prop != NULL)
00219     return (prop->tipo);
00220   else
00221     return ((unsigned char) -1);
00222 }
00223 
00225 
00234 QString Archivero::DaPropiedad (const QString &nom_ent,
00235                                 const QString &nom_prop)
00236 {
00237   const Propiedad *prop = ObtenPropiedad (nom_ent, nom_prop);
00238 
00239   if (prop != NULL)
00240     return (*(prop->contenido));
00241   else
00242     return (QString::null);
00243 }
00244 
00246 
00254 Archivero::Propiedad *Archivero::LeePropiedad (const QString &nom_ent,
00255                                                const QString &nom_prop)
00256 {
00257   Propiedad *propiedad = NULL;
00258 
00259   QDomDocument documento ("entidad");
00260   QDomNode     nodo;
00261   QDomElement  elemento;
00262   QDomAttr     atributo;
00263   QDomText     texto;
00264 
00265   if (!CargaDocumento (documento, nom_ent))
00266     return (NULL);
00267 
00268   elemento = documento.documentElement();
00269   nodo     = elemento.firstChild();
00270   while (!nodo.isNull())
00271   {
00272     elemento = nodo.toElement();
00273     if ((!elemento.isNull()) && (elemento.tagName() != "herencia"))
00274     {
00275       atributo = elemento.attributeNode ("nombre");
00276       // Comparamos el nombre sin distinguir mayúsculas de minúsculas
00277       if ((atributo.value().length() == nom_prop.length()) &&
00278           (atributo.value().startsWith (nom_prop, Qt::CaseInsensitive)))
00279       {
00280         // Hemos encontrado la propiedad
00281         propiedad = new Propiedad (nom_ent, nom_prop);
00282 
00283         if (elemento.tagName() == "rutina")
00284           propiedad->modo = MODO_RUTINA;
00285         else
00286           propiedad->modo = MODO_VARIABLE;
00287 
00288         atributo = elemento.attributeNode ("tipo");
00289         if (atributo.value() == "booleano")
00290           propiedad->tipo = TIPO_BOOLEANO;
00291         else if (atributo.value() == "entero")
00292           propiedad->tipo = TIPO_ENTERO;
00293         else if (atributo.value() == "cadena")
00294           propiedad->tipo = TIPO_CADENA;
00295         else
00296           propiedad->tipo = TIPO_NADA;
00297 
00298         propiedad->contenido = new QString;
00299 
00300         nodo  = nodo.firstChild();
00301         while (!nodo.isNull())
00302         {
00303           texto = nodo.toText();
00304           if (!texto.isNull())
00305             propiedad->contenido->append (texto.data());
00306 
00307           nodo = nodo.nextSibling();
00308         }
00309         break;  // Ya hemos concluido la búsqueda
00310       }
00311     }
00312     nodo = nodo.nextSibling();
00313   }
00314 
00315   if (propiedad == NULL)  // No hemos encontrado la propiedad
00316     return (NULL);
00317 
00318   // Filtramos el contenido de la propiedad
00319   if (propiedad->modo == MODO_RUTINA)
00320   {
00321     *(propiedad->contenido) = FiltroLecturaRutina (*(propiedad->contenido));
00322   }
00323   else if (propiedad->tipo == TIPO_CADENA)
00324   {
00325     bool error;
00326 
00327     *(propiedad->contenido) = FiltroLecturaCadena (*(propiedad->contenido),
00328                                                    error);
00329 
00330     if (error)
00331       qWarning ("\"%s\": Uso incorrecto de \"\\\" en la cadena \"%s\"",
00332                 nom_ent.toLatin1().constData(),
00333                 nom_prop.toLatin1().constData());
00334   }
00335   else if (propiedad->tipo == TIPO_ENTERO)
00336   {
00337     bool error;
00338 
00339     *(propiedad->contenido) = FiltroLecturaEntero (*(propiedad->contenido),
00340                                                    error);
00341 
00342     if (error)
00343       qWarning ("\"%s\": Formato incorrecto del entero \"%s\"",
00344                 nom_ent.toLatin1().constData(),
00345                 nom_prop.toLatin1().constData());
00346   }
00347   else  // propiedad->tipo = TIPO_BOOLEANO
00348   {
00349     bool error;
00350 
00351     *(propiedad->contenido) = FiltroLecturaBooleano (*(propiedad->contenido),
00352                                                      error);
00353 
00354     if (error)
00355       qWarning ("\"%s\": Formato incorrecto del booleano \"%s\"",
00356                 nom_ent.toLatin1().constData(),
00357                 nom_prop.toLatin1().constData());
00358   }
00359 
00360   propiedad->contenido->squeeze();
00361 
00362   return (propiedad);
00363 }
00364 
00366 
00374 const Archivero::Propiedad *Archivero::ObtenPropiedad (const QString &nom_ent,
00375                                                        const QString &nom_prop)
00376 {
00377   // Clave para la búsqueda en las cachés
00378   QString clave (nom_ent + ">" + nom_prop);
00379 
00380   // Nombre de la entidad en la que está almacenada físicamente la propiedad
00381   QString *ent_fisica = rcache.object (clave);
00382 
00383   if (ent_fisica == 0)  // No se ha encontrado en la caché de referencias
00384   {
00385     ent_fisica = new QString (BuscaPropiedad (nom_ent, nom_prop));
00386     if (ent_fisica->isNull())  // No se ha encontrado la entidad o la propiedad
00387     {
00388       delete (ent_fisica);
00389       return (NULL);
00390     }
00391     rcache.insert (clave, ent_fisica, ent_fisica->length());
00392   }
00393 
00394   if (*ent_fisica != nom_ent)
00395     clave = (*ent_fisica + ">" + nom_prop);
00396 
00397   // Propiedad almacenada en la caché de contenidos
00398   Propiedad *propiedad = ccache.object (clave);
00399 
00400   if (propiedad == 0)  // No se ha encontrado en la caché de contenidos
00401   {
00402     propiedad = LeePropiedad (*ent_fisica, nom_prop);
00403     if (propiedad == NULL)
00404     {
00405       // BuscaPropiedad no encuentra las mismas propiedades que LeePropiedad, o
00406       // bien lo que indica rcache es falso
00407       qDebug ("Archivero::ObtenPropiedad(): LeePropiedad() ha devuelto NULL");
00408       return (NULL);
00409     }
00410     ccache.insert (clave, propiedad, propiedad->contenido->length());
00411   }
00412 
00413   return (propiedad);
00414 }
00415 
00416 
00417 // Clase Archivero::Propiedad
00418 
00420 Archivero::Propiedad::Propiedad (const QString &nom_ent,
00421                                  const QString &nom_prop) : entidad (nom_ent),
00422                                                             nombre  (nom_prop)
00423 {
00424   modificada = 0;
00425 }
00426 
00428 Archivero::Propiedad::~Propiedad ()
00429 {
00430   qDebug ("Destructor de Archivero::Propiedad");
00431 
00432   if (modificada)
00433     GuardaPropiedad();
00434 
00435   delete (contenido);
00436 }
00437 
00439 void Archivero::Propiedad::GuardaPropiedad ()
00440 {
00441 }
00442 
00443 
00444 // Funciones fuera de toda clase
00445 
00447 
00454 QString FiltroLecturaBooleano (const QString &original, bool &error)
00455 {
00456   QString filtrado ("F");  // Texto que retornaremos (por defecto FALSO)
00457 
00458   bool hay_booleano = false;  // Si ya se ha encontrado en la cadena un valor
00459                               // booleano ("VERDADERO" o "FALSO")
00460   error             = false;  // Se pondrá a true si se encuentra algún error
00461 
00462   const unsigned long longitud = original.length();
00463 
00464   for (unsigned long i = 0; i < longitud; i++)
00465   {
00466     switch (original.at (i).toLatin1())
00467     {
00468       case ' ' :
00469       case '\n':
00470       case '\r':
00471       case '\t':
00472         break;
00473 
00474       case 'V':
00475         if (hay_booleano || ((i + 8) > longitud) ||
00476             (original.at (i + 1) != 'E') ||
00477             (original.at (i + 2) != 'R') ||
00478             (original.at (i + 3) != 'D') ||
00479             (original.at (i + 4) != 'A') ||
00480             (original.at (i + 5) != 'D') ||
00481             (original.at (i + 6) != 'E') ||
00482             (original.at (i + 7) != 'R') ||
00483             (original.at (i + 8) != 'O'))
00484           error = true;
00485         else
00486         {
00487           hay_booleano = true;
00488           filtrado = "V";
00489         }
00490         break;
00491 
00492       case 'F':
00493         if (hay_booleano || ((i + 5) > longitud) ||
00494             (original.at (i + 1) != 'A') ||
00495             (original.at (i + 2) != 'L') ||
00496             (original.at (i + 3) != 'S') ||
00497             (original.at (i + 4) != 'O'))
00498           error = true;
00499         else
00500           hay_booleano = true;
00501         break;
00502 
00503       default:
00504         error = true;
00505     }
00506     if (error)
00507       break;  // Dejamos de recorrer la cadena original
00508   }
00509 
00510   return (filtrado);
00511 }
00512 
00514 
00521 QString FiltroLecturaCadena (const QString &original, bool &error)
00522 {
00523   QString filtrado;  // Texto que retornaremos
00524 
00525   bool hay_espacio    = false;  // Lo último encontrado es espacio en blanco
00526   bool omitir_espacio = true;   // Omitimos hay_espacio, esto lo haremos al
00527                                 // principio de una nueva línea o tras haber
00528                                 // encontrado espacio explícito
00529   error               = false;  // Se pondrá a true si se encuentra algún error
00530 
00531   const unsigned long longitud = original.length();
00532   const char *cadena = original.toLatin1().constData();
00533 
00534   for (unsigned long i = 0; i < longitud; i++)
00535   {
00536     switch (cadena[i])
00537     {
00538       case ' ' :
00539       case '\n':
00540       case '\r':
00541       case '\t':
00542         hay_espacio = true;
00543         break;
00544 
00545       case '\\':
00546         switch (cadena[i + 1])
00547         {
00548           case 'n':  // Nueva línea explícita
00549             filtrado       += '\n';
00550             omitir_espacio  = true;
00551             break;
00552 
00553           case 't':  // Tabulador explícito
00554             filtrado       += '\t';
00555             omitir_espacio  = true;
00556             break;
00557 
00558           case ' ':  // Espacio explícito
00559             filtrado       += ' ';
00560             omitir_espacio  = true;
00561             break;
00562 
00563           case '\\':  // Barra invertida
00564             if ((!omitir_espacio) && (hay_espacio))
00565             {
00566               filtrado += ' ';
00567             }
00568             filtrado       += '\\';
00569             hay_espacio     = false;
00570             omitir_espacio  = false;
00571             break;
00572 
00573           case '0':
00574           case '1':
00575             if ((cadena[i + 2] < '0') || (cadena[i + 2] > '9') ||
00576                 (cadena[i + 3] < '0') || (cadena[i + 3] > '9'))
00577               error = true;
00578             else  // Código de carácter válido
00579             {
00580               filtrado       += ((cadena[i + 1] - '0') * 100) +
00581                                 ((cadena[i + 2] - '0') * 10) +
00582                                 (cadena[i + 3] - '0');
00583               hay_espacio     = false;
00584               omitir_espacio  = false;
00585             }
00586             i += 2;  // Hemos leído dos caracteres de más
00587             break;
00588 
00589           case '2':
00590             if ((cadena[i + 2] < '0') || (cadena[i + 2] > '5') ||
00591                 (cadena[i + 3] < '0') ||
00592                 (cadena[i + 3] > ((cadena[i + 2] == '5') ? '5' : '9')))
00593               error = true;
00594             else  // Código de carácter válido
00595             {
00596               filtrado       += 200 + ((cadena[i + 2] - '0') * 10) +
00597                                 (cadena[i + 3] - '0');
00598               hay_espacio     = false;
00599               omitir_espacio  = false;
00600             }
00601             i += 2;  // Hemos leído dos caracteres de más
00602             break;
00603 
00604           default:  // Uso incorrecto de la barra invertida
00605             error = true;
00606         }
00607         i += 1;  // Nos saltamos el siguiente carácter
00608         break;
00609 
00610       default:
00611         if ((!omitir_espacio) && (hay_espacio))
00612           filtrado += ' ';  // Espacio implícito
00613         filtrado       += cadena[i];
00614         hay_espacio     = false;
00615         omitir_espacio  = false;
00616     }
00617   }
00618 
00619   return (filtrado);
00620 }
00621 
00623 
00630 QString FiltroLecturaEntero (const QString &original, bool &error)
00631 {
00632   QString filtrado = "0";  // Texto que retornaremos (por defecto 0)
00633 
00634   bool hay_numero = false;  // Si ya se ha encontrado en la cadena un número
00635   bool fin_numero = false;  // Si se encuentra espacio en blanco tras el número
00636   bool negativo   = false;  // El signo del entero es negativo
00637   error           = false;  // Se pondrá a true si se encuentra algún error
00638 
00639   const unsigned long longitud = original.length();
00640 
00641   for (unsigned long i = 0; i < longitud; i++)
00642   {
00643     switch (original.at (i).toLatin1())
00644     {
00645       case ' ' :
00646       case '\n':
00647       case '\r':
00648       case '\t':
00649         if (hay_numero)
00650           fin_numero = true;
00651         break;
00652 
00653       case '+':
00654         if (hay_numero)
00655           error = true;
00656         break;
00657 
00658       case '-':
00659         if (hay_numero)
00660           error = true;
00661         else
00662           negativo = !negativo;
00663         break;
00664 
00665       default:
00666         if (fin_numero || (original.at (i) < '0') || (original.at (i) > '9'))
00667           error = true;
00668         else if (hay_numero)
00669           filtrado += original.at (i);
00670         else if (original.at (i) != '0')  // Omitimos así los ceros iniciales
00671         {
00672           filtrado = original.at (i);
00673           if (negativo)
00674             filtrado.prepend ('-');
00675           hay_numero = true;
00676         }
00677     }
00678     if (error)
00679       break;  // Dejamos de recorrer la cadena original
00680   }
00681 
00682   return (filtrado);
00683 }
00684 
00686 
00691 QString FiltroLecturaRutina (const QString &original)
00692 {
00693   QString filtrado;  // Texto que retornaremos
00694 
00695   bool hay_espacio    = false;  // Lo último encontrado es espacio en blanco
00696   bool omitir_espacio = true;   // Omitimos hay_espacio, esto lo haremos al
00697                                 // principio de una nueva línea
00698 
00699   const unsigned long longitud = original.length();
00700 
00701   for (unsigned long i = 0; i < longitud; i++)
00702   {
00703     switch (original.at (i).toLatin1())
00704     {
00705       case ' ' :
00706       case '\t':
00707         hay_espacio = true;
00708         break;
00709 
00710       case '\n':
00711       case '\r':
00712         // Omitimos caracteres de nueva línea consecutivos
00713         if (!omitir_espacio)
00714         {
00715           filtrado       += '\n';
00716           omitir_espacio  = true;
00717         }
00718   break;
00719 
00720       default:
00721         if ((!omitir_espacio) && (hay_espacio))
00722           filtrado += ' ';  // Espacio implícito
00723         filtrado       += original.at (i);
00724         hay_espacio     = false;
00725         omitir_espacio  = false;
00726     }
00727   }
00728 
00729   return (filtrado);
00730 }
00731 
00733 QString FiltroEscrituraBooleano (const QString &original)
00734 {
00735   QString filtrado;  // Texto que retornaremos
00736 
00737   return (filtrado);
00738 }
00739 
00741 QString FiltroEscrituraCadena (const QString &original)
00742 {
00743   QString filtrado;  // Texto que retornaremos
00744 
00745   return (filtrado);
00746 }
00747 
00749 QString FiltroEscrituraEntero (const QString &original)
00750 {
00751   QString filtrado;  // Texto que retornaremos
00752 
00753   return (filtrado);
00754 }
00755 
00757 QString FiltroEscrituraRutina (const QString &original)
00758 {
00759   QString filtrado;  // Texto que retornaremos
00760 
00761   return (filtrado);
00762 }

Generado el Tue Nov 29 01:04:33 2005 para MUnDoCAAD MUD Engine por  doxygen 1.4.4