1 /*----------------------------------------------------------------------------
2 * jacu - Just Another Compression Utility
3 *----------------------------------------------------------------------------
4 * This file is part of jacu.
6 * jacu is free software; you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation; either version 2 of the License, or (at your option) any later
11 * jacu is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * You should have received a copy of the GNU General Public License along
17 * with jacu; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
19 *----------------------------------------------------------------------------
27 /* Block Sorting Optimizado en memoria! */
29 typedef struct _dict_ {
35 #define PALABRA(a) {a, sizeof(a)-1, 0}
37 #define DICT_SIZE sizeof(dic)/sizeof(t_Diccionario)
39 /* ASCII Numero 3 como caracter de escape */
40 #define ESCAPE_CHARACTER 0x3
43 t_Diccionario dic[] = {
44 /* Preposiciones (no todas) */
50 /* PALABRA(" de"), XXX No se si conviene, solo ahorra 1 byte y puede romper localidad */
97 PALABRA(" existencia"),
104 PALABRA(" portador"),
112 PALABRA(" brillante"),
116 /* Algunas cosas de ingles para mejorar otros textos */
121 PALABRA(" program "),
136 typedef struct _bs_decode_t_ {
141 char es_menor(char *data, t_BlockSort *bs, int i, int j);
143 int _compare(const void *d1, const void *d2) {
144 t_BlockSortDecode *s1, *s2;
146 s1 = (t_BlockSortDecode *)d1;
147 s2 = (t_BlockSortDecode *)d2;
149 /* Hack si es el mismo caracter, dejo como mejor la de menor sig */
150 if (s1->c == s2->c) {
151 return (s1->sig - s2->sig);
154 return (s1->c - s2->c);
157 int __compare(const void *d1, const void *d2) {
158 t_BlockSortData *s1, *s2;
160 s1 = (t_BlockSortData *)d1;
161 s2 = (t_BlockSortData *)d2;
163 return es_menor(s1->bs->data, s1->bs, s1->pos_inicial, s2->pos_inicial);
166 char es_menor(char *data, t_BlockSort *bs, int i, int j)
170 for(k=0; k<bs->len; k++) {
174 if (data[pi] > data[pj]) return 1; /* El primero es mayor */
175 if (data[pi] < data[pj]) return -1; /* El primero es menor */
182 void generar_array(char *data, t_BlockSort *bs)
185 for(i=0; i<bs->len; i++) {
186 bs->array[i].pos_inicial = i;
187 bs->array[i].pos_final = (i+bs->len-1)%bs->len;
188 bs->array[i].ord = (i==0)?1:0;
189 bs->array[i].bs = bs;
193 void ordenar_array(char *data, t_BlockSort *bs)
195 qsort(bs->array, bs->len, sizeof(t_BlockSortData), __compare);
198 int generar_salida(char *data, t_BlockSort *bs, char *salida)
203 /* Dejo lugar para guardar el K */
204 out = salida + sizeof(Uint32);
207 for(i=0; i<bs->len; i++) {
208 out[i] = data[bs->array[i].pos_final];
209 if (bs->array[i].ord == 1) k = i;
214 void bs_solve(char *in, char *out, t_BlockSort *bs, Uint32 *k, Uint32 leido)
218 /* Hack para pedasos menores a la pagina */
219 if (leido < bs->len) bs->len = leido;
222 generar_array(in, bs);
223 ordenar_array(in, bs);
224 (*k) = generar_salida(in, bs, out);
226 /* Guardo el k y el tamaño en el array */
227 memcpy(out, k, sizeof(Uint32));
231 void bs_restore(char *dst, char *c, Uint32 k, Uint32 len)
234 t_BlockSortDecode *in;
236 in = malloc(sizeof(t_BlockSortDecode)*len);
238 for(i=0; i<len; i++) {
243 qsort(in, len, sizeof(t_BlockSortDecode), _compare);
248 dst[i++] = in[current].c;
249 current = in[current].sig;
250 } while (current != k);
254 t_BlockSort *bs_create(Uint32 len)
258 tmp = malloc(sizeof(t_BlockSort));
259 tmp->array = malloc(sizeof(t_BlockSortData)*len);
266 void bs_destroy(t_BlockSort *bs)
273 void bs_EOL(char *data, Uint32 pagesize, Uint32 *j)
275 /* Trato de agregar 4 espacios antes y 4 despues de un \n */
278 /* Verifico poder hacerlo */
279 if ((i+9) >= pagesize) return; /* No pude! */
294 char check_hint(char c)
296 static int current_pos = 0;
301 for(i=0; i<DICT_SIZE; i++) {
302 /* Veo de no pasarme */
303 if (current_pos < dic[i].len) {
304 /* Si la palabra tiene suficientes hints */
305 if (dic[i].hits == current_pos) {
306 if (dic[i].word[current_pos] == c) {
309 if (dic[i].hits == dic[i].len) {
313 /* Esta palabra ya no tiene posibilidades */
326 return -1; /* No hay hints ! */
328 if (hits > 1) return -2; /* Tengo mas de 1 hint! */
330 if (hit_pos == -1) return -2; /* Tengo 1 solo hit pero no es completo */
332 /* Tengo 1 solo hint !!!! */
340 for(i=0; i<DICT_SIZE; i++) {
345 int bs_readblock(FILE *fp, char *data, Uint32 pagesize, int usar_dic)
352 while ((!feof(fp)) && ((i+buffer_pos) < pagesize)) {
360 if (c == ESCAPE_CHARACTER) {
367 hint = check_hint(c);
371 /* No hay hints, vacio el buffer y luego saco el c */
372 for(j=0; j<buffer_pos; j++)
373 data[i++] = buffer[j];
380 /* Tengo mas de 1 hit, tengo posibilidades, guardo este char en el buffer */
381 buffer[buffer_pos++] = c;
384 /* Me retornaron un numero positivo!!, eso quiere decir que ese numero
385 * es la posicion dentro del diccionario de la palabra que puedo reemplazar
387 data[i++] = ESCAPE_CHARACTER;
388 /* Trato de hacer que el caracter sea comun en textos, para que no me rompa
393 /* El buffer no lo necesito mas */
398 for(j=0; j<buffer_pos; j++)
399 data[i++] = buffer[j];
400 /* Saco un EOF que lee de mas */
406 char *bs_finalblock(char *data, Uint32 len, Uint32 *new_size)
412 for(i=0; i < len; i++) {
413 if (data[i] == ESCAPE_CHARACTER) {
415 if (data[i] == 0xF) {
416 /* Solo tengo que dejar el ESCAPE_CHARACTER */
418 out = (char *)realloc(out, size*sizeof(char));
419 out[size-1] = data[i];
420 /* Salteo ese caracter */
422 /* Va una palabra!! */
424 size += dic[(size_t)tmp].len;
425 out = (char *)realloc(out, size*sizeof(char));
426 for(j=0; j<dic[(size_t)tmp].len; j++) {
427 out[size-dic[(size_t)tmp].len+j] = dic[(size_t)tmp].word[j];
429 /* Salteo el caracter siguiente al de escape */
433 out = (char *)realloc(out, size*sizeof(char));
434 out[size-1] = data[i];