#include "lzw.h" #include "utils.h" /** * Constructor. * * \param[in] bVerbose Indica si se tiene que mostrar la información de * depuración o no. */ lzw::lzw(bool bVerbose) { m_bVerbose = bVerbose; } /** * Método para mostrar mensajes de error, y terminar la ejecución * del programa. * * \param[in] msg Mensaje de error para mostrar. */ void lzw::error(string msg) { cerr << "[Error] "<< msg << endl; exit(-1); } /** * Inicializa los valores de la clase. */ void lzw::init() { /** * En primer lugar se inicializan los atributos de la clase, limpiando * el buffer, vaciando las tablas, y pondiendo el índice de lectura a -1. */ m_iComp = -1; m_vBuffer.clear(); m_vTablaCod.clear(); m_vTablaCodInv.clear(); /** * Por último, se genera una tabla inicial, para un alfabeto de 256 * símbolos, correspondientes a los 256 bytes posibles, * del 0000 0000 al 1111 1111. */ for (unsigned int j = 0; j < iLimit; j++) { byte i = static_cast(j); codw index = static_cast(m_vTablaCod.size()); list tmp; tmp.push_back(i); m_vTablaCod[index] = tmp; m_vTablaCodInv[tmp] = index; } } /** * Método que lee un byte del m_vBuffer. * * \param[out] c Byte leido. * \return True en caso de que se haya leido un byte correctamente, y false * false en caso contrario. */ bool lzw::readChar(byte &c) { /** * Usa el atributo m_iComp para acceder a la posición actual de * lectura del m_vBuffer. */ int n = static_cast(m_vBuffer.size()); m_iComp++; if (n == 0 || m_iComp >= n || m_iComp < 0) return false; c = m_vBuffer[m_iComp]; return true; } /** * Método que accede al fichero File, y escribe en este el * código que se le pasa por parámetro. * * \param[in, out] File Referencia del fichero de escritura. * \param[in] Codigo codw */ void lzw::writeCodw (ofstream &File, codw Codigo) { vector aux = codw2byte(Codigo); int n = static_cast(aux.size()); for (int i = 0; i < n; i++) { char c = static_cast(aux[i]); char buffer[1]; buffer[0] = c ; File.write(buffer, 1); } } /** * Método que accede al fichero File, lee lo que ocupa un codw y lo * traduce a un variable de tipo codw. * * \param[in] File Referencia del fichero de lectura. */ codw lzw::readCodw (ifstream &File) { char buffer[1]; File.read(buffer, 1); byte n = static_cast(buffer[0]); vector tmp; for (int i = 0; i < n; i++) { char buffer[1]; File.read(buffer, 1); tmp.push_back(static_cast(buffer[0])); } codw cod = byte2codw(tmp); return cod; } /** * Método que muestra información de depuranción. * * \param[in] buffer Texto que se quiere sacar por pantalla. */ void lzw::debug(const char* buffer) { if (m_bVerbose) cout << "[Debug] "<< buffer << endl; } /** * Método que muestra información de depuranción. * * \param[in] buffer Texto que se quiere sacar por pantalla. */ void lzw::debug(string buffer) { if (m_bVerbose) cout << "[Debug] "<< buffer << endl; } /** * Método que muestra información de depuranción. * * \param[in] buffer Texto que se quiere sacar por pantalla. */ void lzw::debug(int buffer) { if (m_bVerbose) cout << "[Debug] "<< buffer << endl; } /** * Método que lee el fichero a comprimir, y además contruye el diccionario * inicial. * * \param[in] sFile Dirección donde se encuentra el fichero a comprimir. */ void lzw::readSource (string sFile) { ifstream file(sFile.c_str(), ifstream::binary); if (!file.is_open()) error (string("No se pudo abrir el archivo de origen: ") + sFile); byte cCaracter; char buffer[1]; while (!file.read(buffer, 1).eof()) { cCaracter = static_cast(buffer[0]); m_vBuffer.push_back(cCaracter); } file.close(); } /** * Método que implementa el algoritmo de copresión. * * \param[in] sFileIn Dirección del fichero que se quiere comprimir. * \param[in] sFileOut Dirección donde se dejara el fichero comprimido. */ void lzw::compress (string sFileIn, string sFileOut) { debug("### INICIO COMPRESION ###"); debug(string("Fichero de entrada: ") + sFileIn ); init(); readSource(sFileIn); debug(string("Fichero de salida: ") + sFileOut ); ofstream file(sFileOut.c_str(), ofstream::binary); if (!file.is_open()) error (string("No se pudo abrir el archivo de destino: ") + sFileOut); vector vBufferSalida; list sCadena; byte cCaracter; while (readChar(cCaracter)) { list sTmp(sCadena); sTmp.push_back(cCaracter); if (m_vTablaCodInv.find(sTmp) != m_vTablaCodInv.end()) { sCadena = sTmp; } else { /** * - Añadir sTmp al diccionario. */ codw index = static_cast(m_vTablaCod.size()); m_vTablaCod[index] = sTmp; m_vTablaCodInv[sTmp]= index; /** * - Emitir índice de sCadena */ vBufferSalida.push_back(m_vTablaCodInv[sCadena]); sCadena.clear(); sCadena.push_back(cCaracter); } } /** * Hay que tener en cuenta que la codificación del último * carácter nunca se podrá emitir, por lo tanto se pierde * información. */ if (sCadena.size() != 0 ) { if (m_vTablaCodInv.find(sCadena) != m_vTablaCodInv.end()) { vBufferSalida.push_back(m_vTablaCodInv[sCadena]); } else { list sTmp; byte c = sCadena.back(); sTmp.push_back(c); sCadena.pop_back(); vBufferSalida.push_back(m_vTablaCodInv[sCadena]); vBufferSalida.push_back(m_vTablaCodInv[sTmp]); } } debug("Escribiendo fichero comprimido..."); int n = static_cast(vBufferSalida.size()); for (int i = 0; i < n; i++) { writeCodw(file, vBufferSalida[i]); } file.close(); debug("### FIN COMPRESION ###"); } /** * Método que implementa el algoritmo de descopresión. * * \param[in] sFileIn Dirección del fichero que se quiere descomprimir. * \param[in] sFileOut Dirección donde se dejara el fichero descomprimido. */ void lzw::uncompress (string sFileIn, string sFileOut) { debug("### INICIO DESCOMPRESION ###"); init(); ifstream fileIn(sFileIn.c_str(), ifstream::binary); ofstream fileOut(sFileOut.c_str(), ofstream::binary); debug("Leyendo fichero..."); codw iCodigoAnterior; codw iCodigo; iCodigo = readCodw(fileIn); list lTmp = m_vTablaCod[iCodigo]; for (list::iterator it = lTmp.begin(); it != lTmp.end(); it++) { char buffer[1]; buffer[0] = static_cast(*it); fileOut.write(buffer, 1); } iCodigoAnterior = iCodigo; while (!fileIn.eof()) { iCodigo = readCodw(fileIn); if (m_vTablaCod.find(iCodigo) != m_vTablaCod.end()) { /** * Hay que tener en cuenta el caso en el que el índice * leido está en la tabla. */ list lTmp = m_vTablaCod[iCodigo]; for (list::iterator it = lTmp.begin(); it != lTmp.end(); it++) { char buffer[1]; buffer[0] = static_cast(*it); fileOut.write(buffer, 1); } list lTmp2 = m_vTablaCod[iCodigoAnterior]; lTmp2.push_back(lTmp.front()); codw index = static_cast(m_vTablaCod.size()); m_vTablaCod[index] = lTmp2; m_vTablaCodInv[lTmp2]= index; } else { /** * Y el caso en el que NO está en la tabla. */ list lTmp = m_vTablaCod[iCodigoAnterior]; lTmp.push_back(lTmp.front()); for (list::iterator it = lTmp.begin(); it != lTmp.end(); it++) { char buffer[1]; buffer[0] = static_cast(*it); fileOut.write(buffer, 1); } codw index = static_cast(m_vTablaCod.size()); m_vTablaCod[index] = lTmp; m_vTablaCodInv[lTmp]= index; } iCodigoAnterior = iCodigo; } debug("FIN"); fileIn.close(); fileOut.close(); debug("### FIN DESCOMPRESION ###"); }