Uso de la librerÃa UnRarLib con C++
Extrayendo bytes de nuestro recurso
El método read extraerá bytes de nuestro archivo o buffer de memoria, en el caso de ser un archivo convencional nuestros métodos serán indirecciones a los método homónimos de la clase ifstream (el precio que debemos pagar por la transparencia), pero si no lo es se comportará como si lo fuera para el resto del programa ¡y esto es muy bueno!. Veamos el flujo:

Figura 2. El flujo del método read
Analizando el flujo del método read, podemos apreciar que existe una división en dos partes: si hemos abierto un archivo convencional o si hemos abierto un archivo comprimido.
La idea aquà es manejar un buffer de memoria como si fuese un stream, para esto requerimos mantener mediante un cursor (una propiedad del tipo número entero) que nos indique en que parte del “archivo” estamos situados. De este modo cuando copiemos la información de un buffer a otro, lo haremos relativamente al cursor, es decir, en función de donde estemos parados dentro de nuestro buffer.
A esto debemos sumarle la verificación de no pasarnos en la lectura de nuestro buffer de memoria, ya que si lo hacemos podrÃamos generar un error de violación de acceso, tras lo cual nuestro programa se cerrarÃa abruptamente. Es decir, si nuestro buffer es de 34 bytes y el usuario nos solicita leer 64 bytes, entonces deberemos leer el máximo e informarle (mediante el valor de retorno de la función) que hemos leÃdo menos información de la solicitada.
Luego, la verificación del “end of file” (eof) para nuestro buffer de memoria será simplemente verificar si el cursor posee un valor inferior al tamaño total del buffer.
La implementación del seek, respecto al buffer de memoria, consiste simplemente en realizar cuentas con la propiedad cursor verificando siempre dejarla en valores válidos (entre cero y el tamaño máximo del archivo).
Los métodos especiales
Finalmente agregaremos algunos métodos más a nuestra clase ifstreamrar que nos serán muy útiles pero sólo tendrán sentido cuando estemos hablando de recursos empaquetados.
. getFirstElement
. getNextElement
Estos métodos nos permitirán inspeccionar el contenido de un archivo empaquetado, es decir, mirar los archivos que posee comprimidos en su interior. Los prototipos de ambas funciones son iguales:
bool getFirstElement(char * pszPackFilename, char * pszElementName, int iMaxElementNameLength, unsigned long & ulPackedSize, unsigned long & ulUnPackedSize);
bool getNextElement(char * pszPackFilename, char * pszElementName, int iMaxElementNameLength, unsigned long & ulPackedSize, unsigned long & ulUnPackedSize);
pszPackFilename : Nombre del archivo empaquetado (entrada)
pszElementName : Nombre del elemento primero o siguiente dentro del archivo empaquetado (salida)
iMaxElementNameLength : Tamaño total del buffer pasado como parámetro para que el método copie el nombre del elemento (entrada)
ulPackedSize : Tamaño en bytes del elemento comprimido (salida)
ulUnPackedSize : Tamaño en bytes del elemento sin comprimir (salida)
Como utilizar nuestra clase ifstreamrar
Veamos tres casos tÃpicos de uso de nuestra flamante clase.
Abrir un archivo convencional o recurso comprimido
En este primer caso haremos uso de la facilidad de transparencia que adicional la clase ifstreamrar a nuestro proyecto. Intentaremos abrir un recurso de nuestro sistema sin saber necesariamente si el mismo se encuentra comprimido o no.
Para esto bastarán las siguientes lÃneas de código:
| char * pszBuf = NULL;
| // Abro el recurso
| if (ifs.open("./res/archivo_prueba_1.txt"))
| {
| // Dimensiono el buffer en donde copiaré los datos
| // descomprimidos
| pszBuf = new char[ifs.getSize()];
|
| // Obtengo el contenido del archivo
| ifs.read(pszBuf, ifs.getSize());
|
| // Cierro el recurso
| ifs.close();
| }
| else
| cout << "No pudo abrirse el recurso" << endl;
En el listado anterior utilizo sólo tres métodos de mi clase:
open: Para abrir el empaquetado o el archivo.
read: Para leer los datos del archivo abierto o del item perteneciente al empaquetado.
close: Para cerrar el empaquetado o el archivo.
Obtener el listado de elementos de un empaquetado
Para obtener el listado del contenido de elementos comprimidos dentro de un empaquetado utilizaremos los métodos getFirstResource y getNextResource del siguiente modo:
| char szElementName[512];
| unsigned long ulPackedSize;
| unsigned long ulUnpackedSize;
| bool bRes = ifs.getFirstResource("./res.rar", szElementName, 512, ulPackedSize, ulUnpackedSize);
|
| while (bRes)
| {
| // Muestro el contenido de un elemento a pantalla
| cout << szElementName << " (packed: " << ulPackedSize << ", unpacked: " << ulUnpackedSize << ")" << endl;
|
| // Tomo el siguiente elemento
| bRes = ifs.getNextResource("./res.rar", szElementName, 512, ulPackedSize, ulUnpackedSize);
| }
Invocamos una vez getFirstResource y si el valor de retorno es verdadero ingresamos dentro de un bucle donde el corte de control se encuentra dado por el valor de retorno del método getNextResource, que es invocado en la última lÃnea del bucle, tarde o temprano el listado llegará a su fin y este método nos retornará falso.
De cada las propiedades de cada elemento, el par de métodos retorna: nombre, tamaño de elemento comprimido y tamaño del elemento sin comprimir (de estas dos últimas propiedades se puede calcular la relación de compresión).
Empaquetados con contraseña
El último caso de uso de un empaquetado es una variedad del primero, simplemente agregamos una contraseña para tornar un poquito más difÃcil la tarea de algún curioso. Se basa en utilizar un segundo parámetro del método open que está declarado como opcional y es la contraseña que se utilizará para abrir el empaquetado.
| // …
| if (ifs.open("./res_passwd/archivo_prueba_1.txt", "code"))
| // …
Otras librerÃas de compresión

Conclusiones
Las razones por las cuales podrÃamos desear incorporar esta facilidad a nuestros juegos son variadas: podrÃamos querer ocultar los archivos utilizados para evitar su modificación (ej: archivos del tipo bmp, jpg, wav, mid, txt, etc.), podrÃamos querer disminuir el tamaño total de nuestra aplicación (¡hasta un 80%!), podrÃamos querer facilitar la distribución de nuestra aplicación (distribución comprimir sin requerir instalación), etc.
Ahora sólo resta que experimentes un poco y agregues esta caracterÃstica a tu próximo juego.
~fuzzyLogic





Comentarios (2)



MUY interesante articulo. Es realmente un tema a resolver, cuando todo el “content” del juego esta creado, pero en infinidad de archivos sueltos, produciendo fragmentacion en el disco, lentitud durante la instalacion, y perdida de performance debido a los tiempos de acceso, y multiples I/O.
Cabe destacar, sin embargo, algunos problemas relacionados con el formato elegido. Por empezar, RAR es un formato propietario, y eso genera dos situaciones:
1) Los archivos RAR que utilicemos deberan estár creados con herramientas pagas, y no con la propia libreria unRarLib, con la que solo podremos descomprimir (se pierde asi la capacidad de empaquetado/compresion para, por ej. los savegames).
2) La licencia de unRarLib se concede bajo dos condiciones: GPL License, que implica codigo abierto obligado en la aplicaion que utilice UnRarLib, o, UnRarLib License segun la cual, todo desarrollo que utilice la libreria, no podra ser comercializado, osea, debera ser gratuito.
A los problemas de licencia, deberiamos adicionarle la siguiente cuestion: el formato RAR es uno de los mas eficientes a la hora de comprimir, pero al coste de un elevado “computational time”, en comparacion con otros formatos de compresion. Esto nos deja con el dilema: quiero espacio, o quiero performance? en la industria de los videojuegos, esa pregunta se responde sola, y en mayusculas, VELOCIDAD!!!!
Ya que el problema principal es el empaquetado, y no la compresion, podemos considerar usar el formato, pero sin comprimir. Pero asi perdemos la virtud del formato, que es justamente la capacidad de compresion, y quedamos en igualdad de condiciones frente a cualquier otro. Y ante igualdad de condiciones tecnicas, y problemas de licencia, mejor elegir otro formato… Pero esa claro, es mi humilde opinion. Saludos.
P.D.: Fuzzy, con todo esto quiero decir: el pueblo pide un tutorial con otro formato!!!
thank you, brother