NovaMonoFix
Errores PHP
X
Usuario
Password
0 FPS

Tutorial WinAPI C++ 3.9 (Creación del ObjetoZLIB)

06 de Noviembre del 2010 por Josep Antoni Bover, 0 visitas, 0 comentarios, 0 votos
Categorías : Windows, Programación, C y C++.
La web está en segundo plano, animación en pausa.
Cargando animación...
Tutorial WinAPI C++ 3.9 (Creación del ObjetoZLIB)

En este tutorial vamos a encapsular las funciones de la ZLIB (libreria de compresion y descompresion escrita por Jean-loup-Gailly y Mark Adler) en un objeto que usaremos tanto en la aplicacion Instalador como en la aplicacion Ensamblador.

De esta forma nos crearemos un objeto que con una linea de codigo sera capaz de comprimir / descomprimir un archivo, y asi no tendremos que preocuparnos mas por este tema una vez creemos las aplicaciones finales de este tutorial.

Lo primero será diseñar un contenedor al que se le puedan agregar partes binarias, que será el destinado a contener los archivos comprimidos / descomprimidos en memoria. Para ello crearemos el objeto ContenedorBinario, veamos su declaración :

Archivo : ObjetoZLIB.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
// Clase destinada a contener datos comprimidos
// Se ha hecho de forma que se puede agregar un archivo por partes de tamaño variable.
class ContenedorBinario {
public : //////// Miembros publicos
// -Constructor
ContenedorBinario(void) {
_Longitud = 0;
_Datos = NULL;
};
// -Destructor
~ContenedorBinario(void) {
if (_Datos != NULL) delete [] _Datos;
};
// -Función para agregar una parte
void AgregarParte(const char *NuevaParte, const size_t LongitudParte) {
char *NuevosDatos = new char [_Longitud + LongitudParte];
if (_Datos != NULL) {
CopyMemory(NuevosDatos, _Datos, _Longitud);
delete [] _Datos;
}
CopyMemory(&NuevosDatos[_Longitud], NuevaParte, LongitudParte);
_Datos = NuevosDatos;
_Longitud += LongitudParte;
};
// -Operador que retorna una referencia a los datos
// de esta clase en la posición especificada
char *operator[] (const UINT nPos) {
return &_Datos[nPos];
};
// -Operador que retorna la posicion de inicio de
// los datos que contiene esta clase
char *operator() (void) const {
return _Datos;
};
// -Función que retorna el tamaño total de los datos de esta clase
UINT Longitud(void) const {
return _Longitud;
};
// -Función que borra los datos de esta clase
void Borrar(void) {
_Longitud = 0;
if (_Datos != NULL) delete [] _Datos;
_Datos = NULL;
};
protected : ///// Miembros protegidos
// -Miembro que contiene los datos agregados
char *_Datos;
// -Miembro que contiene el tamaño de la variable _Datos
UINT _Longitud;
};

Este objeto nos permite ir agregando partes binarias variables de forma que queden concatenadas. Esto se hace así porque la ZLIB tanto para comprimir como para descomprimir lo hace por trozos. Además en nuestro caso necesitamos añadir todos los archivos comprimidos a un solo archivo, por lo que la mejor opción es mantener el archivo comprimido en memoria.

Ahora veamos la declaración del ObjetoZLIB :

Archivo : ObjetoZLIB.h
1
2
3
4
5
6
7
8
9
10
11
12
// Clase que contiene las funciones necesarias para ensamblar el instalador, y para instalarse
class ObjetoZLIB {
public : //////////////////// Miembros publicos
// -Constructor
ObjetoZLIB(void);
// -Destructor
~ObjetoZLIB(void);
// -Función que comprime un archivo dentro de una clase ContenedorBinario
const BOOL Comprimir(const TCHAR *nPathOrigen, ContenedorBinario &Datos);
// -Función que descomprime un ContenedorBinario y lo guarda en nPathDestino como un archivo
const BOOL Descomprimir(ContenedorBinario &Datos, const TCHAR *nPathDestino);
};

Este objeto tiene dos métodos públicos : Comprimir y Descomprimir.

Veamos la función Comprimir :

Archivo : ObjetoZLIB.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const BOOL ObjetoZLIB::Comprimir(const TCHAR *nPathOrigen, ContenedorBinario &Datos) {
ObjetoArchivo Origen;
Datos.Borrar();
// Si el archivo origen no se puede abrir retornamos FALSE
if (Origen.AbrirArchivoLectura(nPathOrigen) == false) return FALSE;
int ret, flush;
unsigned have;
z_stream strm;
char in[CHUNK];
char out[CHUNK];
// Inicialización
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, 5);
if (ret != Z_OK) return FALSE;
// Comprimimos hasta el final del archivo
do {
strm.avail_in = Origen.Leer(&in, CHUNK * sizeof(char));
flush = Origen.FinalDelArchivo() ? Z_FINISH : Z_NO_FLUSH;
strm.next_in = reinterpret_cast<Bytef *>(&in[0]);
// Ejecutamos deflate hasta que comprimamos todo el archivo
do {
strm.avail_out = CHUNK;
strm.next_out = reinterpret_cast<Bytef *>(&out[0]);
ret = deflate(&strm, flush);
have = CHUNK - strm.avail_out;
Datos.AgregarParte(out, have);
} while (strm.avail_out == 0);
} while (flush != Z_FINISH);
// Liberamos la memoria usada por la zlib
deflateEnd(&strm);
return TRUE;
}

Esta función abre el archivo a comprimir, lee el archivo a partes, comprime cada parte, y introduce las partes dentro del ContenedorBinario.

Y por último la función Descomprimir :

Archivo : ObjetoZLIB.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const BOOL ObjetoZLIB::Descomprimir(ContenedorBinario &Datos, const TCHAR *nPathDestino) {
ObjetoArchivo Destino;
// Si el archivo destino no se puede abrir retornamos FALSE
if (Destino.AbrirArchivoEscritura(nPathDestino, true) == FALSE) return FALSE;
int ret;
unsigned have;
z_stream strm;
char in[CHUNK] = "";
char out[CHUNK] = "";
unsigned int Posicion = 0;
// Inicialización
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK) return FALSE;
// Descomprimimos hasta que se terminen los datos
do {
if (Posicion + CHUNK < Datos.Longitud()) {
memcpy(in, Datos[Posicion], CHUNK);
strm.avail_in = CHUNK;
}
else {
memcpy(in, Datos[Posicion], Datos.Longitud() - Posicion);
strm.avail_in = Datos.Longitud() - Posicion;
}
Posicion += CHUNK;
if (strm.avail_in == 0)
break;
strm.next_in = reinterpret_cast<Bytef *>(&in[0]);
// Ejecutamos inflate para extraer los datos
do {
strm.avail_out = CHUNK;
strm.next_out = reinterpret_cast<Bytef *>(&out[0]);
ret = inflate(&strm, Z_NO_FLUSH);
switch (ret) {
case Z_NEED_DICT:
ret = Z_DATA_ERROR;
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return ret;
}
have = CHUNK - strm.avail_out;
Destino.Guardar(out, have);
} while (strm.avail_out == 0);
// Terminamos cuando inflate retorne Z_STREAM_END
} while (ret != Z_STREAM_END);
// Liberamos la memoria usada por la ZLIB
inflateEnd(&strm);
return (ret == Z_STREAM_END) ? TRUE : FALSE;
}

Esta función abre el archivo a descomprimir, lee el ContenedorBinario por partes, descomprime cada parte, y va guardando las partes descomprimidas en el path destino.

Con esto ya tenemos todos los requisitos para crear el instalador.

Siguiente tutorial : 3.10 Terminando el Instalador