1 /* Made up from data.c and other supplementary files of dictd-1.0.11 for the
2  * GoldenDict program.
3  */
4 
5 /* data.c --
6  * Created: Tue Jul 16 12:45:41 1996 by faith@dict.org
7  * Revised: Sat Mar 30 10:46:06 2002 by faith@dict.org
8  * Copyright 1996, 1997, 1998, 2000, 2002 Rickard E. Faith (faith@dict.org)
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the
12  * Free Software Foundation; either version 1, or (at your option) any
13  * later version.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License along
21  * with this program; if not, write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Suite 500, Boston, MA 02110, USA.
23  */
24 
25 #include <stdlib.h>
26 #include <time.h>
27 #include "dictzip.h"
28 #include <limits.h>
29 #include <stdarg.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "ufile.hh"
35 
36 #define BUFFERSIZE 10240
37 
38 #define OUT_BUFFER_SIZE 0xffffL
39 
40 #define IN_BUFFER_SIZE ((unsigned long)((double)(OUT_BUFFER_SIZE - 12) * 0.89))
41 
42 /* For gzip-compatible header, as defined in RFC 1952 */
43 
44 				/* Magic for GZIP (rfc1952)                */
45 #define GZ_MAGIC1     0x1f	/* First magic byte                        */
46 #define GZ_MAGIC2     0x8b	/* Second magic byte                       */
47 
48 				/* FLaGs (bitmapped), from rfc1952         */
49 #define GZ_FTEXT      0x01	/* Set for ASCII text                      */
50 #define GZ_FHCRC      0x02	/* Header CRC16                            */
51 #define GZ_FEXTRA     0x04	/* Optional field (random access index)    */
52 #define GZ_FNAME      0x08	/* Original name                           */
53 #define GZ_COMMENT    0x10	/* Zero-terminated, human-readable comment */
54 #define GZ_MAX           2	/* Maximum compression                     */
55 #define GZ_FAST          4	/* Fasted compression                      */
56 
57 				/* These are from rfc1952                  */
58 #define GZ_OS_FAT        0	/* FAT filesystem (MS-DOS, OS/2, NT/Win32) */
59 #define GZ_OS_AMIGA      1	/* Amiga                                   */
60 #define GZ_OS_VMS        2	/* VMS (or OpenVMS)                        */
61 #define GZ_OS_UNIX       3      /* Unix                                    */
62 #define GZ_OS_VMCMS      4      /* VM/CMS                                  */
63 #define GZ_OS_ATARI      5      /* Atari TOS                               */
64 #define GZ_OS_HPFS       6      /* HPFS filesystem (OS/2, NT)              */
65 #define GZ_OS_MAC        7      /* Macintosh                               */
66 #define GZ_OS_Z          8      /* Z-System                                */
67 #define GZ_OS_CPM        9      /* CP/M                                    */
68 #define GZ_OS_TOPS20    10      /* TOPS-20                                 */
69 #define GZ_OS_NTFS      11      /* NTFS filesystem (NT)                    */
70 #define GZ_OS_QDOS      12      /* QDOS                                    */
71 #define GZ_OS_ACORN     13      /* Acorn RISCOS                            */
72 #define GZ_OS_UNKNOWN  255      /* unknown                                 */
73 
74 #define GZ_RND_S1       'R'	/* First magic for random access format    */
75 #define GZ_RND_S2       'A'	/* Second magic for random access format   */
76 
77 #define GZ_ID1           0	/* GZ_MAGIC1                               */
78 #define GZ_ID2           1	/* GZ_MAGIC2                               */
79 #define GZ_CM            2	/* Compression Method (Z_DEFALTED)         */
80 #define GZ_FLG	         3	/* FLaGs (see above)                       */
81 #define GZ_MTIME         4	/* Modification TIME                       */
82 #define GZ_XFL           8	/* eXtra FLags (GZ_MAX or GZ_FAST)         */
83 #define GZ_OS            9	/* Operating System                        */
84 #define GZ_XLEN         10	/* eXtra LENgth (16bit)                    */
85 #define GZ_FEXTRA_START 12	/* Start of extra fields                   */
86 #define GZ_SI1          12	/* Subfield ID1                            */
87 #define GZ_SI2          13      /* Subfield ID2                            */
88 #define GZ_SUBLEN       14	/* Subfield length (16bit)                 */
89 #define GZ_VERSION      16      /* Version for subfield format             */
90 #define GZ_CHUNKLEN     18	/* Chunk length (16bit)                    */
91 #define GZ_CHUNKCNT     20	/* Number of chunks (16bit)                */
92 #define GZ_RNDDATA      22	/* Random access data (16bit)              */
93 
94 
95 #define DBG_VERBOSE     (0<<30|1<< 0) /* Verbose                            */
96 #define DBG_ZIP         (0<<30|1<< 1) /* Zip                                */
97 #define DBG_UNZIP       (0<<30|1<< 2) /* Unzip                              */
98 #define DBG_SEARCH      (0<<30|1<< 3) /* Search                             */
99 #define DBG_SCAN        (0<<30|1<< 4) /* Config file scan                   */
100 #define DBG_PARSE       (0<<30|1<< 5) /* Config file parse                  */
101 #define DBG_INIT        (0<<30|1<< 6) /* Database initialization            */
102 #define DBG_PORT        (0<<30|1<< 7) /* Log port number for connections    */
103 #define DBG_LEV         (0<<30|1<< 8) /* Levenshtein matching               */
104 #define DBG_AUTH        (0<<30|1<< 9) /* Debug authentication               */
105 #define DBG_NODETACH    (0<<30|1<<10) /* Don't detach as a background proc. */
106 #define DBG_NOFORK      (0<<30|1<<11) /* Don't fork (single threaded)       */
107 #define DBG_ALT         (0<<30|1<<12) /* altcompare()                      */
108 
109 #define LOG_SERVER      (0<<30|1<< 0) /* Log server diagnostics             */
110 #define LOG_CONNECT     (0<<30|1<< 1) /* Log connection information         */
111 #define LOG_STATS       (0<<30|1<< 2) /* Log termination information        */
112 #define LOG_COMMAND     (0<<30|1<< 3) /* Log commands                       */
113 #define LOG_FOUND       (0<<30|1<< 4) /* Log words found                    */
114 #define LOG_NOTFOUND    (0<<30|1<< 5) /* Log words not found                */
115 #define LOG_CLIENT      (0<<30|1<< 6) /* Log client                         */
116 #define LOG_HOST        (0<<30|1<< 7) /* Log remote host name               */
117 #define LOG_TIMESTAMP   (0<<30|1<< 8) /* Log with timestamps                */
118 #define LOG_MIN         (0<<30|1<< 9) /* Log a few minimal things           */
119 #define LOG_AUTH        (0<<30|1<<10) /* Log authentication denials         */
120 
121 #define DICT_LOG_TERM    0
122 #define DICT_LOG_DEFINE  1
123 #define DICT_LOG_MATCH   2
124 #define DICT_LOG_NOMATCH 3
125 #define DICT_LOG_CLIENT  4
126 #define DICT_LOG_TRACE   5
127 #define DICT_LOG_COMMAND 6
128 #define DICT_LOG_AUTH    7
129 #define DICT_LOG_CONNECT 8
130 
131 #define DICT_UNKNOWN    0
132 #define DICT_TEXT       1
133 #define DICT_GZIP       2
134 #define DICT_DZIP       3
135 
136 #include <ctype.h>
137 #include <fcntl.h>
138 #include <assert.h>
139 
140 #include <sys/stat.h>
141 
142 #define USE_CACHE 1
143 
144 #define dict_data_filter( ... )
145 #define PRINTF( ... )
146 
147 #define xmalloc malloc
148 #define xfree free
149 
150 static const char * _err_programName = "GoldenDict";
151 
152 #define log_error( ... )
153 #define log_error_va( ... )
154 
err_fatal(const char * routine,const char * format,...)155 static void err_fatal( const char *routine, const char *format, ... )
156 {
157    va_list ap;
158 
159    fflush( stdout );
160    if (_err_programName) {
161       if (routine)
162 	 fprintf( stderr, "%s (%s): ", _err_programName, routine );
163       else
164 	 fprintf( stderr, "%s: ", _err_programName );
165    } else {
166       if (routine) fprintf( stderr, "%s: ", routine );
167    }
168 
169    va_start( ap, format );
170    vfprintf( stderr, format, ap );
171    log_error_va( routine, format, ap );
172    va_end( ap );
173 
174    fflush( stderr );
175    fflush( stdout );
176 //   exit ( 1 );
177 }
178 
179 /* \doc |err_fatal_errno| flushes "stdout", prints a fatal error report on
180    "stderr", prints the system error corresponding to |errno|, flushes
181    "stderr" and "stdout", and calls |exit|.  |routine| is the name of the
182    routine in which the error took place. */
183 
err_fatal_errno(const char * routine,const char * format,...)184 static void err_fatal_errno( const char *routine, const char *format, ... )
185 {
186    va_list ap;
187    int     errorno = errno;
188 
189    fflush( stdout );
190    if (_err_programName) {
191       if (routine)
192 	 fprintf( stderr, "%s (%s): ", _err_programName, routine );
193       else
194 	 fprintf( stderr, "%s: ", _err_programName );
195    } else {
196       if (routine) fprintf( stderr, "%s: ", routine );
197    }
198 
199    va_start( ap, format );
200    vfprintf( stderr, format, ap );
201    log_error_va( routine, format, ap );
202    va_end( ap );
203 
204 #if HAVE_STRERROR
205    fprintf( stderr, "%s: %s\n", routine, strerror( errorno ) );
206    log_error( routine, "%s: %s\n", routine, strerror( errorno ) );
207 #else
208    errno = errorno;
209    perror( routine );
210    log_error( routine, "%s: errno = %d\n", routine, errorno );
211 #endif
212 
213    fflush( stderr );
214    fflush( stdout );
215 //   exit( 1 );
216 }
217 
218 /* \doc |err_internal| flushes "stdout", prints the fatal error message,
219    flushes "stderr" and "stdout", and calls |abort| so that a core dump is
220    generated. */
221 
err_internal(const char * routine,const char * format,...)222 static void err_internal( const char *routine, const char *format, ... )
223 {
224   va_list ap;
225 
226   fflush( stdout );
227   if (_err_programName) {
228      if (routine)
229   fprintf( stderr, "%s (%s): Internal error\n     ",
230      _err_programName, routine );
231      else
232   fprintf( stderr, "%s: Internal error\n     ", _err_programName );
233   } else {
234      if (routine) fprintf( stderr, "%s: Internal error\n     ", routine );
235      else         fprintf( stderr, "Internal error\n     " );
236   }
237 
238   va_start( ap, format );
239   vfprintf( stderr, format, ap );
240   log_error( routine, format, ap );
241   va_end( ap );
242 
243   if (_err_programName)
244      fprintf( stderr, "Aborting %s...\n", _err_programName );
245   else
246      fprintf( stderr, "Aborting...\n" );
247   fflush( stderr );
248   fflush( stdout );
249 //  abort();
250 }
251 
252 #ifndef __func__
253 # ifdef __FUNCTION__
254 #  define __func__  __FUNCTION__
255 # else
256 #  define __func__  __FILE__
257 # endif
258 #endif
259 
dict_read_header(const char * filename,dictData * header,int computeCRC)260 static enum  DZ_ERRORS dict_read_header( const char *filename,
261 					 dictData *header,
262 					 int computeCRC )
263 {
264    FILE          *str;
265    int           id1, id2, si1, si2;
266    char          buffer[BUFFERSIZE];
267    int           extraLength, subLength;
268    int           i;
269    char          *pt;
270    int           c;
271    struct stat   sb;
272    unsigned long crc   = crc32( 0L, Z_NULL, 0 );
273    int           count;
274    unsigned long offset;
275 
276    if (!(str = gd_fopen( filename, "rb" )))
277    {
278       err_fatal_errno( __func__,
279 		       "Cannot open data file \"%s\" for read\n", filename );
280       return DZ_ERR_OPENFILE;
281    }
282 
283    header->filename     = NULL;//str_find( filename );
284    header->headerLength = GZ_XLEN - 1;
285    header->type         = DICT_UNKNOWN;
286 
287    id1                  = getc( str );
288    id2                  = getc( str );
289 
290    if (id1 != GZ_MAGIC1 || id2 != GZ_MAGIC2) {
291       header->type = DICT_TEXT;
292       fstat( fileno( str ), &sb );
293       header->compressedLength = header->length = sb.st_size;
294       header->origFilename     = NULL;//str_find( filename );
295       header->mtime            = sb.st_mtime;
296       if (computeCRC) {
297 	 rewind( str );
298 	 while (!feof( str )) {
299 	    if ((count = fread( buffer, 1, BUFFERSIZE, str ))) {
300 	       crc = crc32( crc, (Bytef *)buffer, count );
301 	    }
302 	 }
303       }
304       header->crc = crc;
305       fclose( str );
306       return DZ_NOERROR;
307    }
308    header->type = DICT_GZIP;
309 
310    header->method       = getc( str );
311    header->flags        = getc( str );
312    header->mtime        = getc( str ) <<  0;
313    header->mtime       |= getc( str ) <<  8;
314    header->mtime       |= getc( str ) << 16;
315    header->mtime       |= getc( str ) << 24;
316    header->extraFlags   = getc( str );
317    header->os           = getc( str );
318 
319    if (header->flags & GZ_FEXTRA) {
320       extraLength          = getc( str ) << 0;
321       extraLength         |= getc( str ) << 8;
322       header->headerLength += extraLength + 2;
323       si1                  = getc( str );
324       si2                  = getc( str );
325 
326       if (si1 == GZ_RND_S1 && si2 == GZ_RND_S2) {
327 	 subLength            = getc( str ) << 0;
328 	 subLength           |= getc( str ) << 8;
329 	 header->version      = getc( str ) << 0;
330 	 header->version     |= getc( str ) << 8;
331 
332 	 if (header->version != 1)
333 	 {
334 	    err_internal( __func__,
335 			  "dzip header version %d not supported\n",
336 			  header->version );
337 	    fclose( str );
338 	    return DZ_ERR_UNSUPPORTED_FORMAT;
339 	 }
340 
341 	 header->chunkLength  = getc( str ) << 0;
342 	 header->chunkLength |= getc( str ) << 8;
343 	 header->chunkCount   = getc( str ) << 0;
344 	 header->chunkCount  |= getc( str ) << 8;
345 
346 	 if (header->chunkCount <= 0) {
347 	    fclose( str );
348 	    return DZ_ERR_INVALID_FORMAT;
349 	 }
350 	 header->chunks = xmalloc( sizeof( header->chunks[0] )
351 				   * header->chunkCount );
352 	 if( header->chunks == 0 ) {
353 	   return DZ_ERR_NOMEMORY;
354 	 }
355 
356 	 for (i = 0; i < header->chunkCount; i++) {
357 	    header->chunks[i]  = getc( str ) << 0;
358 	    header->chunks[i] |= getc( str ) << 8;
359 	 }
360 	 header->type = DICT_DZIP;
361       } else {
362 	 fseek( str, header->headerLength, SEEK_SET );
363       }
364    }
365 
366    if (header->flags & GZ_FNAME) { /* FIXME! Add checking against header len */
367       pt = buffer;
368       while ((c = getc( str )) && c != EOF){
369 	 *pt++ = c;
370 
371 	 if (pt == buffer + sizeof (buffer)){
372 	    err_fatal (
373 	       __func__,
374 	       "too long FNAME field in dzip file \"%s\"\n", filename);
375 	    fclose( str );
376 	    if( header->chunks )
377 	      free( header->chunks );
378 	    return DZ_ERR_INVALID_FORMAT;
379 	 }
380       }
381 
382       *pt = '\0';
383       header->origFilename = NULL;//str_find( buffer );
384       header->headerLength += strlen( buffer ) + 1;
385    } else {
386       header->origFilename = NULL;
387    }
388 
389    if (header->flags & GZ_COMMENT) { /* FIXME! Add checking for header len */
390       pt = buffer;
391       while ((c = getc( str )) && c != EOF){
392 	 *pt++ = c;
393 
394 	 if (pt == buffer + sizeof (buffer)){
395 	    err_fatal (
396 	       __func__,
397 	       "too long COMMENT field in dzip file \"%s\"\n", filename);
398 	    fclose( str );
399 	    if( header->chunks )
400 	      free( header->chunks );
401 	    return DZ_ERR_INVALID_FORMAT;
402 	 }
403       }
404 
405       *pt = '\0';
406       header->comment = NULL;//str_find( buffer );
407       header->headerLength += strlen( buffer ) + 1;
408    } else {
409       header->comment = NULL;
410    }
411 
412    if (header->flags & GZ_FHCRC) {
413       getc( str );
414       getc( str );
415       header->headerLength += 2;
416    }
417 
418    if (ftell( str ) != header->headerLength + 1)
419    {
420       err_internal( __func__,
421 		    "File position (%lu) != header length + 1 (%d)\n",
422 		    ftell( str ), header->headerLength + 1 );
423       fclose( str );
424       if( header->chunks )
425         free( header->chunks );
426       return DZ_ERR_INVALID_FORMAT;
427    }
428 
429    fseek( str, -8, SEEK_END );
430    header->crc     = getc( str ) <<  0;
431    header->crc    |= getc( str ) <<  8;
432    header->crc    |= getc( str ) << 16;
433    header->crc    |= getc( str ) << 24;
434    header->length  = getc( str ) <<  0;
435    header->length |= getc( str ) <<  8;
436    header->length |= getc( str ) << 16;
437    header->length |= getc( str ) << 24;
438    header->compressedLength = ftell( str );
439 
440 				/* Compute offsets */
441    header->offsets = xmalloc( sizeof( header->offsets[0] )
442 			      * header->chunkCount );
443    if( header->offsets == 0 ) {
444      if( header->chunks )
445        free( header->chunks );
446      return DZ_ERR_NOMEMORY;
447    }
448 
449    for (offset = header->headerLength + 1, i = 0;
450 	i < header->chunkCount;
451 	i++)
452    {
453       header->offsets[i] = offset;
454       offset += header->chunks[i];
455    }
456 
457    fclose( str );
458    return DZ_NOERROR;
459 }
460 
dict_data_open(const char * filename,enum DZ_ERRORS * error,int computeCRC)461 dictData *dict_data_open( const char *filename,
462                           enum DZ_ERRORS * error,
463                           int computeCRC )
464 {
465    dictData    *h = NULL;
466 //   struct stat sb;
467    int         j;
468 
469    if (!filename)
470    {
471      *error = DZ_ERR_OPENFILE;
472      return NULL;
473    }
474 
475    h = xmalloc( sizeof( struct dictData ) );
476    if( h == 0 )
477    {
478      *error = DZ_ERR_NOMEMORY;
479      return 0;
480    }
481 
482    memset( h, 0, sizeof( struct dictData ) );
483 #ifdef __WIN32
484    h->fd = INVALID_HANDLE_VALUE;
485 #endif
486    h->initialized = 0;
487 
488    for(;;)
489    {
490 #ifdef __WIN32
491      wchar_t wname[16384];
492 #endif
493      *error = dict_read_header( filename, h, computeCRC );
494      if ( *error != DZ_NOERROR ) {
495        break; /*
496         err_fatal( __func__,
497        "\"%s\" not in text or dzip format\n", filename );*/
498      }
499 
500 #ifdef __WIN32
501      if( MultiByteToWideChar( CP_UTF8, 0, filename, -1, wname, 16384 ) == 0 )
502      {
503        *error = DZ_ERR_OPENFILE;
504        break;
505      }
506 
507      h->fd = CreateFileW( wname, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
508                           OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
509      if( h->fd == INVALID_HANDLE_VALUE )
510      {
511        *error = DZ_ERR_OPENFILE;
512        break;
513      }
514 
515      h->size = GetFileSize( h->fd, 0 );
516 #else
517      h->fd = gd_fopen( filename, "rb" );
518 
519      if ( !h->fd )
520      {
521        *error = DZ_ERR_OPENFILE;
522        break;
523         /*err_fatal_errno( __func__,
524              "Cannot open data file \"%s\"\n", filename );*/
525       }
526 
527      fseek( h->fd, 0, SEEK_END );
528 
529      h->size = ftell( h->fd );
530 #endif
531 
532      for (j = 0; j < DICT_CACHE_SIZE; j++) {
533         h->cache[j].chunk    = -1;
534         h->cache[j].stamp    = -1;
535         h->cache[j].inBuffer = NULL;
536         h->cache[j].count    = 0;
537      }
538 
539      *error = DZ_NOERROR;
540      return h;
541    }
542    dict_data_close( h );
543    return( 0 );
544 }
545 
dict_data_close(dictData * header)546 void dict_data_close( dictData *header )
547 {
548    int i;
549 
550    if (!header)
551       return;
552 
553 #ifdef __WIN32
554    if ( header->fd != INVALID_HANDLE_VALUE )
555      CloseHandle( header->fd );
556 #else
557    if ( header->fd )
558      fclose( header->fd );
559 #endif
560 
561    if (header->chunks)       xfree( header->chunks );
562    if (header->offsets)      xfree( header->offsets );
563 
564    if (header->initialized) {
565       if (inflateEnd( &header->zStream ))
566 	 err_internal( __func__,
567 		       "Cannot shut down inflation engine: %s\n",
568 		       header->zStream.msg );
569    }
570 
571    for (i = 0; i < DICT_CACHE_SIZE; ++i){
572       if (header -> cache [i].inBuffer)
573 	 xfree (header -> cache [i].inBuffer);
574    }
575 
576    memset( header, 0, sizeof( struct dictData ) );
577    xfree( header );
578 }
579 
dict_data_read_(dictData * h,unsigned long start,unsigned long size,const char * preFilter,const char * postFilter)580 char *dict_data_read_ (
581    dictData *h, unsigned long start, unsigned long size,
582    const char *preFilter, const char *postFilter )
583 {
584    char * buffer;
585    char * pt;
586    unsigned long end;
587    int           count;
588    char          *inBuffer;
589    char          outBuffer[OUT_BUFFER_SIZE];
590    int           firstChunk, lastChunk;
591    int           firstOffset, lastOffset;
592    int           i, j;
593    int           found, target, lastStamp;
594    (void) preFilter;
595    (void) postFilter;
596 
597    end  = start + size;
598 
599    buffer = xmalloc( size + 1 );
600    if( !buffer )
601    {
602      strcpy( h->errorString, dz_error_str( DZ_ERR_NOMEMORY ) );
603      return 0;
604    }
605 
606    if ( !size )
607    {
608      *buffer = 0;
609      return buffer;
610    }
611 
612    PRINTF(DBG_UNZIP,
613 	  ("dict_data_read( %p, %lu, %lu, %s, %s )\n",
614 	   h, start, size, preFilter, postFilter ));
615 
616    assert( h != NULL);
617    switch (h->type) {
618    case DICT_GZIP:
619 /*
620       err_fatal( __func__,
621 		 "Cannot seek on pure gzip format files.\n"
622 		 "Use plain text (for performance)"
623 		 " or dzip format (for space savings).\n" );
624       break;
625 */
626       strcpy( h->errorString, "Cannot seek on pure gzip format files" );
627       xfree( buffer );
628       return 0;
629    case DICT_TEXT:
630    {
631 #ifdef __WIN32
632      long hiPtr = 0;
633      DWORD pos = SetFilePointer( h->fd, start, &hiPtr, FILE_BEGIN );
634      DWORD readed = 0;
635      if( pos != INVALID_SET_FILE_POINTER || GetLastError() != NO_ERROR )
636        ReadFile( h->fd, buffer, size, &readed, 0 );
637      if( size != readed )
638 #else
639      if ( fseek( h->fd, start, SEEK_SET ) != 0 ||
640           fread( buffer, size, 1, h->fd ) != 1 )
641 #endif
642      {
643        strcpy( h->errorString, dz_error_str( DZ_ERR_READFILE ) );
644        xfree( buffer );
645        return 0;
646      }
647 
648      buffer[size] = '\0';
649    }
650    break;
651    case DICT_DZIP:
652       if (!h->initialized) {
653 	 h->zStream.zalloc    = NULL;
654 	 h->zStream.zfree     = NULL;
655 	 h->zStream.opaque    = NULL;
656 	 h->zStream.next_in   = 0;
657 	 h->zStream.avail_in  = 0;
658 	 h->zStream.next_out  = NULL;
659 	 h->zStream.avail_out = 0;
660 	 if (inflateInit2( &h->zStream, -15 ) != Z_OK)
661 /*
662 	    err_internal( __func__,
663 			  "Cannot initialize inflation engine: %s\n",
664 			  h->zStream.msg );
665 */
666 	 {
667 	   sprintf( h->errorString, "Cannot initialize inflation engine: %s", h->zStream.msg );
668 	   xfree( buffer );
669 	   return 0;
670 	 }
671 	 ++h->initialized;
672       }
673       firstChunk  = start / h->chunkLength;
674       firstOffset = start - firstChunk * h->chunkLength;
675       lastChunk   = end / h->chunkLength;
676       lastOffset  = end - lastChunk * h->chunkLength;
677       PRINTF(DBG_UNZIP,
678 	     ("   start = %lu, end = %lu\n"
679 	      "firstChunk = %d, firstOffset = %d,"
680 	      " lastChunk = %d, lastOffset = %d\n",
681 	      start, end, firstChunk, firstOffset, lastChunk, lastOffset ));
682       for (pt = buffer, i = firstChunk; i <= lastChunk; i++) {
683 
684 				/* Access cache */
685 	 found  = 0;
686 	 target = 0;
687 	 lastStamp = INT_MAX;
688 	 for (j = 0; j < DICT_CACHE_SIZE; j++) {
689 #if USE_CACHE
690 	    if (h->cache[j].chunk == i) {
691 	       found  = 1;
692 	       target = j;
693 	       break;
694 	    }
695 #endif
696 	    if (h->cache[j].stamp < lastStamp) {
697 	       lastStamp = h->cache[j].stamp;
698 	       target = j;
699 	    }
700 	 }
701 
702 	 h->cache[target].stamp = ++h->stamp;
703 	 if( h->stamp < 0 )
704 	 {
705 	    h->stamp = 0;
706 	    for (j = 0; j < DICT_CACHE_SIZE; j++)
707 	      h->cache[j].stamp = -1;
708 	 }
709 	 if (found) {
710 	    count = h->cache[target].count;
711 	    inBuffer = h->cache[target].inBuffer;
712 	 } else {
713 #ifdef __WIN32
714         DWORD pos ;
715         DWORD readed;
716 #endif
717 	    h->cache[target].chunk = -1;
718 	    if (!h->cache[target].inBuffer)
719 	       h->cache[target].inBuffer = xmalloc( h->chunkLength );
720 	    inBuffer = h->cache[target].inBuffer;
721 	    if( !inBuffer )
722 	    {
723 	      strcpy( h->errorString, dz_error_str( DZ_ERR_NOMEMORY ) );
724 	      xfree( buffer );
725 	      return 0;
726 	    }
727 
728 	    if (h->chunks[i] >= OUT_BUFFER_SIZE ) {
729 /*
730 	       err_internal( __func__,
731 			     "h->chunks[%d] = %d >= %ld (OUT_BUFFER_SIZE)\n",
732 			     i, h->chunks[i], OUT_BUFFER_SIZE );
733 */
734               sprintf( h->errorString, "h->chunks[%d] = %d >= %ld (OUT_BUFFER_SIZE)\n",
735                        i, h->chunks[i], OUT_BUFFER_SIZE );
736               xfree( buffer );
737               return 0;
738 	    }
739 
740 #ifdef __WIN32
741       pos = SetFilePointer( h->fd, h->offsets[ i ], 0, FILE_BEGIN );
742       readed = 0;
743       if( pos != INVALID_SET_FILE_POINTER || GetLastError() != NO_ERROR )
744         ReadFile( h->fd, outBuffer, h->chunks[ i ], &readed, 0 );
745       if( h->chunks[ i ] != (int)readed )
746 #else
747       if ( fseek( h->fd, h->offsets[ i ], SEEK_SET ) != 0 ||
748            fread( outBuffer, h->chunks[ i ], 1, h->fd ) != 1 )
749 #endif
750       {
751         strcpy( h->errorString, dz_error_str( DZ_ERR_READFILE ) );
752         xfree( buffer );
753         return 0;
754       }
755 
756       dict_data_filter( outBuffer, &count, OUT_BUFFER_SIZE, preFilter );
757 
758 	    h->zStream.next_in   = (Bytef *)outBuffer;
759 	    h->zStream.avail_in  = h->chunks[i];
760 	    h->zStream.next_out  = (Bytef *)inBuffer;
761 	    h->zStream.avail_out = h->chunkLength;
762 	    if (inflate( &h->zStream,  Z_PARTIAL_FLUSH ) != Z_OK)
763 	    {
764 //	       err_fatal( __func__, "inflate: %s\n", h->zStream.msg );
765 	      sprintf( h->errorString, "inflate: %s\n", h->zStream.msg );
766 	      xfree( buffer );
767 	      return 0;
768 	    }
769 	    if (h->zStream.avail_in)
770 /*
771 	       err_internal( __func__,
772 			     "inflate did not flush (%d pending, %d avail)\n",
773 			     h->zStream.avail_in, h->zStream.avail_out );
774 */
775 	    {
776 	      sprintf( h->errorString, "inflate did not flush (%d pending, %d avail)\n",
777 		       h->zStream.avail_in, h->zStream.avail_out );
778 	      xfree( buffer );
779 	      return 0;
780 	    }
781 
782 	    count = h->chunkLength - h->zStream.avail_out;
783       dict_data_filter( inBuffer, &count, h->chunkLength, postFilter );
784 
785 	    h->cache[target].count = count;
786 	    h->cache[target].chunk = i;
787 	 }
788 
789 	 if (i == firstChunk) {
790 	    if (i == lastChunk) {
791 	       memcpy( pt, inBuffer + firstOffset, lastOffset-firstOffset);
792 	       pt += lastOffset - firstOffset;
793 	    } else {
794 	       if (count != h->chunkLength )
795 /*
796 		  err_internal( __func__,
797 				"Length = %d instead of %d\n",
798 				count, h->chunkLength );
799 */
800 	       {
801 		 sprintf( h->errorString, "Length = %d instead of %d\n",
802 			  count, h->chunkLength );
803 		 xfree( buffer );
804 		 return 0;
805 	       }
806 	       memcpy( pt, inBuffer + firstOffset,
807 		       h->chunkLength - firstOffset );
808 	       pt += h->chunkLength - firstOffset;
809 	    }
810 	 } else if (i == lastChunk) {
811 	    memcpy( pt, inBuffer, lastOffset );
812 	    pt += lastOffset;
813 	 } else {
814 	    assert( count == h->chunkLength );
815 	    memcpy( pt, inBuffer, h->chunkLength );
816 	    pt += h->chunkLength;
817 	 }
818       }
819       *pt = '\0';
820       break;
821    case DICT_UNKNOWN:
822 //      err_fatal( __func__, "Cannot read unknown file type\n" );
823       strcpy( h->errorString, "Cannot read unknown file type" );
824       xfree( buffer );
825       return 0;
826    }
827    h->errorString[ 0 ] = 0;
828    return buffer;
829 }
830 
dict_error_str(dictData * data)831 char *dict_error_str( dictData *data )
832 {
833   return data->errorString;
834 }
835 
dz_error_str(enum DZ_ERRORS error)836 const char * dz_error_str( enum DZ_ERRORS error )
837 {
838   switch( error )
839   {
840     case DZ_NOERROR:                return "No error";
841     case DZ_ERR_OPENFILE:           return "Open file error";
842     case DZ_ERR_READFILE:           return "Read file error";
843     case DZ_ERR_INVALID_FORMAT:     return "Invalid file format";
844     case DZ_ERR_UNSUPPORTED_FORMAT: return "Unsupported file format";
845     case DZ_ERR_NOMEMORY:           return "Memory allocation error";
846     case DZ_ERR_INTERNAL:           return "Internal error";
847   }
848   return "Unknown error";
849 }
850