mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / storage / archive / azio.c
blobaaf8233a30c0ba0d54427e2604b8d4b5bb33450b
1 /*
2 azio is a modified version of gzio. It makes use of mysys and removes mallocs.
3 -Brian Aker
4 */
6 /* gzio.c -- IO on .gz files
7 * Copyright (C) 1995-2005 Jean-loup Gailly.
8 * For conditions of distribution and use, see copyright notice in zlib.h
12 /* @(#) $Id$ */
14 #include "azlib.h"
16 #include <stdio.h>
17 #include <string.h>
19 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
20 static int const az_magic[3] = {0xfe, 0x03, 0x01}; /* az magic header */
22 /* gzip flag uchar */
23 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
24 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
25 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
26 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
27 #define COMMENT 0x10 /* bit 4 set: file comment present */
28 #define RESERVED 0xE0 /* bits 5..7: reserved */
30 int az_open(azio_stream *s, const char *path, int Flags, File fd);
31 int do_flush(azio_stream *file, int flush);
32 int get_byte(azio_stream *s);
33 void check_header(azio_stream *s);
34 void write_header(azio_stream *s);
35 int destroy(azio_stream *s);
36 void putLong(File file, uLong x);
37 uLong getLong(azio_stream *s);
38 void read_header(azio_stream *s, unsigned char *buffer);
40 /* ===========================================================================
41 Opens a gzip (.gz) file for reading or writing. The mode parameter
42 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
43 or path name (if fd == -1).
44 az_open returns NULL if the file could not be opened or if there was
45 insufficient memory to allocate the (de)compression state; errno
46 can be checked to distinguish the two cases (if errno is zero, the
47 zlib error is Z_MEM_ERROR).
49 int az_open (azio_stream *s, const char *path, int Flags, File fd)
51 int err;
52 int level = Z_DEFAULT_COMPRESSION; /* compression level */
53 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
55 s->stream.zalloc = (alloc_func)0;
56 s->stream.zfree = (free_func)0;
57 s->stream.opaque = (voidpf)0;
58 memset(s->inbuf, 0, AZ_BUFSIZE_READ);
59 memset(s->outbuf, 0, AZ_BUFSIZE_WRITE);
60 s->stream.next_in = s->inbuf;
61 s->stream.next_out = s->outbuf;
62 s->stream.avail_in = s->stream.avail_out = 0;
63 s->z_err = Z_OK;
64 s->z_eof = 0;
65 s->in = 0;
66 s->out = 0;
67 s->back = EOF;
68 s->crc = crc32(0L, Z_NULL, 0);
69 s->transparent = 0;
70 s->mode = 'r';
71 s->version = (unsigned char)az_magic[1]; /* this needs to be a define to version */
72 s->minor_version= (unsigned char) az_magic[2]; /* minor version */
73 s->dirty= AZ_STATE_CLEAN;
76 We do our own version of append by nature.
77 We must always have write access to take card of the header.
79 DBUG_ASSERT(Flags | O_APPEND);
80 DBUG_ASSERT(Flags | O_WRONLY);
82 if (Flags & O_RDWR)
83 s->mode = 'w';
85 if (s->mode == 'w')
87 err = deflateInit2(&(s->stream), level,
88 Z_DEFLATED, -MAX_WBITS, 8, strategy);
89 /* windowBits is passed < 0 to suppress zlib header */
91 s->stream.next_out = s->outbuf;
92 if (err != Z_OK)
94 destroy(s);
95 return Z_NULL;
97 } else {
98 s->stream.next_in = s->inbuf;
100 err = inflateInit2(&(s->stream), -MAX_WBITS);
101 /* windowBits is passed < 0 to tell that there is no zlib header.
102 * Note that in this case inflate *requires* an extra "dummy" byte
103 * after the compressed stream in order to complete decompression and
104 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
105 * present after the compressed stream.
107 if (err != Z_OK)
109 destroy(s);
110 return Z_NULL;
113 s->stream.avail_out = AZ_BUFSIZE_WRITE;
115 errno = 0;
116 s->file = fd < 0 ? my_open(path, Flags, MYF(0)) : fd;
117 DBUG_EXECUTE_IF("simulate_archive_open_failure",
119 if (s->file >= 0)
121 my_close(s->file, MYF(0));
122 s->file= -1;
123 my_errno= EMFILE;
127 if (s->file < 0 )
129 destroy(s);
130 return Z_NULL;
133 if (Flags & O_CREAT || Flags & O_TRUNC)
135 s->rows= 0;
136 s->forced_flushes= 0;
137 s->shortest_row= 0;
138 s->longest_row= 0;
139 s->auto_increment= 0;
140 s->check_point= 0;
141 s->comment_start_pos= 0;
142 s->comment_length= 0;
143 s->frm_start_pos= 0;
144 s->frm_length= 0;
145 s->dirty= 1; /* We create the file dirty */
146 s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
147 write_header(s);
148 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
150 else if (s->mode == 'w')
152 uchar buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
153 my_pread(s->file, buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
154 MYF(0));
155 read_header(s, buffer); /* skip the .az header */
156 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
158 else
160 check_header(s); /* skip the .az header */
163 return 1;
167 void write_header(azio_stream *s)
169 char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
170 char *ptr= buffer;
172 s->block_size= AZ_BUFSIZE_WRITE;
173 s->version = (unsigned char)az_magic[1];
174 s->minor_version = (unsigned char)az_magic[2];
177 /* Write a very simple .az header: */
178 memset(buffer, 0, AZHEADER_SIZE + AZMETA_BUFFER_SIZE);
179 *(ptr + AZ_MAGIC_POS)= az_magic[0];
180 *(ptr + AZ_VERSION_POS)= (unsigned char)s->version;
181 *(ptr + AZ_MINOR_VERSION_POS)= (unsigned char)s->minor_version;
182 *(ptr + AZ_BLOCK_POS)= (unsigned char)(s->block_size/1024); /* Reserved for block size */
183 *(ptr + AZ_STRATEGY_POS)= (unsigned char)Z_DEFAULT_STRATEGY; /* Compression Type */
185 int4store(ptr + AZ_FRM_POS, s->frm_start_pos); /* FRM Block */
186 int4store(ptr + AZ_FRM_LENGTH_POS, s->frm_length); /* FRM Block */
187 int4store(ptr + AZ_COMMENT_POS, s->comment_start_pos); /* COMMENT Block */
188 int4store(ptr + AZ_COMMENT_LENGTH_POS, s->comment_length); /* COMMENT Block */
189 int4store(ptr + AZ_META_POS, 0); /* Meta Block */
190 int4store(ptr + AZ_META_LENGTH_POS, 0); /* Meta Block */
191 int8store(ptr + AZ_START_POS, (unsigned long long)s->start); /* Start of Data Block Index Block */
192 int8store(ptr + AZ_ROW_POS, (unsigned long long)s->rows); /* Start of Data Block Index Block */
193 int8store(ptr + AZ_FLUSH_POS, (unsigned long long)s->forced_flushes); /* Start of Data Block Index Block */
194 int8store(ptr + AZ_CHECK_POS, (unsigned long long)s->check_point); /* Start of Data Block Index Block */
195 int8store(ptr + AZ_AUTOINCREMENT_POS, (unsigned long long)s->auto_increment); /* Start of Data Block Index Block */
196 int4store(ptr+ AZ_LONGEST_POS , s->longest_row); /* Longest row */
197 int4store(ptr+ AZ_SHORTEST_POS, s->shortest_row); /* Shorest row */
198 int4store(ptr+ AZ_FRM_POS,
199 AZHEADER_SIZE + AZMETA_BUFFER_SIZE); /* FRM position */
200 *(ptr + AZ_DIRTY_POS)= (unsigned char)s->dirty; /* Start of Data Block Index Block */
202 /* Always begin at the begining, and end there as well */
203 my_pwrite(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
204 MYF(0));
207 /* ===========================================================================
208 Opens a gzip (.gz) file for reading or writing.
210 int azopen(azio_stream *s, const char *path, int Flags)
212 return az_open(s, path, Flags, -1);
215 /* ===========================================================================
216 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
217 to mimic the behavio(u)r of fdopen.
219 int azdopen(azio_stream *s, File fd, int Flags)
221 if (fd < 0) return 0;
223 return az_open (s, NULL, Flags, fd);
226 /* ===========================================================================
227 Read a byte from a azio_stream; update next_in and avail_in. Return EOF
228 for end of file.
229 IN assertion: the stream s has been sucessfully opened for reading.
231 int get_byte(s)
232 azio_stream *s;
234 if (s->z_eof) return EOF;
235 if (s->stream.avail_in == 0)
237 errno = 0;
238 s->stream.avail_in= (uInt) my_read(s->file, (uchar *)s->inbuf,
239 AZ_BUFSIZE_READ, MYF(0));
240 if (s->stream.avail_in == 0)
242 s->z_eof = 1;
243 return EOF;
245 else if (s->stream.avail_in == (uInt) -1)
247 s->z_eof= 1;
248 s->z_err= Z_ERRNO;
249 return EOF;
251 s->stream.next_in = s->inbuf;
253 s->stream.avail_in--;
254 return *(s->stream.next_in)++;
257 /* ===========================================================================
258 Check the gzip header of a azio_stream opened for reading. Set the stream
259 mode to transparent if the gzip magic header is not present; set s->err
260 to Z_DATA_ERROR if the magic header is present but the rest of the header
261 is incorrect.
262 IN assertion: the stream s has already been created sucessfully;
263 s->stream.avail_in is zero for the first time, but may be non-zero
264 for concatenated .gz files.
266 void check_header(azio_stream *s)
268 int method; /* method uchar */
269 int flags; /* flags uchar */
270 uInt len;
271 int c;
273 /* Assure two bytes in the buffer so we can peek ahead -- handle case
274 where first byte of header is at the end of the buffer after the last
275 gzip segment */
276 len = s->stream.avail_in;
277 if (len < 2) {
278 if (len) s->inbuf[0] = s->stream.next_in[0];
279 errno = 0;
280 len = (uInt)my_read(s->file, (uchar *)s->inbuf + len, AZ_BUFSIZE_READ >> len, MYF(0));
281 if (len == (uInt)-1) s->z_err = Z_ERRNO;
282 s->stream.avail_in += len;
283 s->stream.next_in = s->inbuf;
284 if (s->stream.avail_in < 2) {
285 s->transparent = s->stream.avail_in;
286 return;
290 /* Peek ahead to check the gzip magic header */
291 if ( s->stream.next_in[0] == gz_magic[0] && s->stream.next_in[1] == gz_magic[1])
293 s->stream.avail_in -= 2;
294 s->stream.next_in += 2;
295 s->version= (unsigned char)2;
297 /* Check the rest of the gzip header */
298 method = get_byte(s);
299 flags = get_byte(s);
300 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
301 s->z_err = Z_DATA_ERROR;
302 return;
305 /* Discard time, xflags and OS code: */
306 for (len = 0; len < 6; len++) (void)get_byte(s);
308 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
309 len = (uInt)get_byte(s);
310 len += ((uInt)get_byte(s))<<8;
311 /* len is garbage if EOF but the loop below will quit anyway */
312 while (len-- != 0 && get_byte(s) != EOF) ;
314 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
315 while ((c = get_byte(s)) != 0 && c != EOF) ;
317 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
318 while ((c = get_byte(s)) != 0 && c != EOF) ;
320 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
321 for (len = 0; len < 2; len++) (void)get_byte(s);
323 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
324 s->start = my_tell(s->file, MYF(0)) - s->stream.avail_in;
326 else if ( s->stream.next_in[0] == az_magic[0] && s->stream.next_in[1] == az_magic[1])
328 unsigned char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
330 for (len = 0; len < (AZHEADER_SIZE + AZMETA_BUFFER_SIZE); len++)
331 buffer[len]= get_byte(s);
332 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
333 read_header(s, buffer);
334 for (; len < s->start; len++)
335 get_byte(s);
337 else
339 s->z_err = Z_OK;
341 return;
345 void read_header(azio_stream *s, unsigned char *buffer)
347 if (buffer[0] == az_magic[0] && buffer[1] == az_magic[1])
349 s->version= (unsigned int)buffer[AZ_VERSION_POS];
350 s->minor_version= (unsigned int)buffer[AZ_MINOR_VERSION_POS];
351 s->block_size= 1024 * buffer[AZ_BLOCK_POS];
352 s->start= (unsigned long long)uint8korr(buffer + AZ_START_POS);
353 s->rows= (unsigned long long)uint8korr(buffer + AZ_ROW_POS);
354 s->check_point= (unsigned long long)uint8korr(buffer + AZ_CHECK_POS);
355 s->forced_flushes= (unsigned long long)uint8korr(buffer + AZ_FLUSH_POS);
356 s->auto_increment= (unsigned long long)uint8korr(buffer + AZ_AUTOINCREMENT_POS);
357 s->longest_row= (unsigned int)uint4korr(buffer + AZ_LONGEST_POS);
358 s->shortest_row= (unsigned int)uint4korr(buffer + AZ_SHORTEST_POS);
359 s->frm_start_pos= (unsigned int)uint4korr(buffer + AZ_FRM_POS);
360 s->frm_length= (unsigned int)uint4korr(buffer + AZ_FRM_LENGTH_POS);
361 s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS);
362 s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS);
363 s->dirty= (unsigned int)buffer[AZ_DIRTY_POS];
365 else if (buffer[0] == gz_magic[0] && buffer[1] == gz_magic[1])
368 Set version number to previous version (2).
370 s->version= (unsigned char) 2;
371 } else {
373 Unknown version.
374 Most probably due to a corrupt archive.
376 s->dirty= AZ_STATE_DIRTY;
377 s->z_err= Z_VERSION_ERROR;
381 /* ===========================================================================
382 * Cleanup then free the given azio_stream. Return a zlib error code.
383 Try freeing in the reverse order of allocations.
385 int destroy (s)
386 azio_stream *s;
388 int err = Z_OK;
390 if (s->stream.state != NULL)
392 if (s->mode == 'w')
393 err = deflateEnd(&(s->stream));
394 else if (s->mode == 'r')
395 err = inflateEnd(&(s->stream));
398 if (s->file > 0 && my_close(s->file, MYF(0)))
399 err = Z_ERRNO;
401 s->file= -1;
403 if (s->z_err < 0) err = s->z_err;
405 return err;
408 /* ===========================================================================
409 Reads the given number of uncompressed bytes from the compressed file.
410 azread returns the number of bytes actually read (0 for end of file).
412 unsigned int ZEXPORT azread ( azio_stream *s, voidp buf, size_t len, int *error)
414 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
415 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
416 *error= 0;
418 if (s->mode != 'r')
420 *error= Z_STREAM_ERROR;
421 return 0;
424 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
426 *error= s->z_err;
427 return 0;
430 if (s->z_err == Z_STREAM_END) /* EOF */
432 return 0;
435 next_out = (Byte*)buf;
436 s->stream.next_out = (Bytef*)buf;
437 s->stream.avail_out = len;
439 if (s->stream.avail_out && s->back != EOF) {
440 *next_out++ = s->back;
441 s->stream.next_out++;
442 s->stream.avail_out--;
443 s->back = EOF;
444 s->out++;
445 start++;
446 if (s->last) {
447 s->z_err = Z_STREAM_END;
449 return 1;
454 while (s->stream.avail_out != 0) {
456 if (s->transparent) {
457 /* Copy first the lookahead bytes: */
458 uInt n = s->stream.avail_in;
459 if (n > s->stream.avail_out) n = s->stream.avail_out;
460 if (n > 0) {
461 memcpy(s->stream.next_out, s->stream.next_in, n);
462 next_out += n;
463 s->stream.next_out = (Bytef *)next_out;
464 s->stream.next_in += n;
465 s->stream.avail_out -= n;
466 s->stream.avail_in -= n;
468 if (s->stream.avail_out > 0)
470 s->stream.avail_out -=
471 (uInt)my_read(s->file, (uchar *)next_out, s->stream.avail_out, MYF(0));
473 len -= s->stream.avail_out;
474 s->in += len;
475 s->out += len;
476 if (len == 0) s->z_eof = 1;
478 return len;
481 if (s->stream.avail_in == 0 && !s->z_eof) {
483 errno = 0;
484 s->stream.avail_in = (uInt)my_read(s->file, (uchar *)s->inbuf, AZ_BUFSIZE_READ, MYF(0));
485 if (s->stream.avail_in == 0)
487 s->z_eof = 1;
489 s->stream.next_in = (Bytef *)s->inbuf;
491 s->in += s->stream.avail_in;
492 s->out += s->stream.avail_out;
493 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
494 s->in -= s->stream.avail_in;
495 s->out -= s->stream.avail_out;
497 if (s->z_err == Z_STREAM_END) {
498 /* Check CRC and original size */
499 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
500 start = s->stream.next_out;
502 if (getLong(s) != s->crc) {
503 s->z_err = Z_DATA_ERROR;
504 } else {
505 (void)getLong(s);
506 /* The uncompressed length returned by above getlong() may be
507 * different from s->out in case of concatenated .gz files.
508 * Check for such files:
510 check_header(s);
511 if (s->z_err == Z_OK)
513 inflateReset(&(s->stream));
514 s->crc = crc32(0L, Z_NULL, 0);
518 if (s->z_err != Z_OK || s->z_eof) break;
520 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
522 if (len == s->stream.avail_out &&
523 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
525 *error= s->z_err;
527 return 0;
530 return (len - s->stream.avail_out);
534 /* ===========================================================================
535 Writes the given number of uncompressed bytes into the compressed file.
536 azwrite returns the number of bytes actually written (0 in case of error).
538 unsigned int azwrite (azio_stream *s, const voidp buf, unsigned int len)
540 s->stream.next_in = (Bytef*)buf;
541 s->stream.avail_in = len;
543 s->rows++;
545 while (s->stream.avail_in != 0)
547 if (s->stream.avail_out == 0)
550 s->stream.next_out = s->outbuf;
551 if (my_write(s->file, (uchar *)s->outbuf, AZ_BUFSIZE_WRITE,
552 MYF(0)) != AZ_BUFSIZE_WRITE)
554 s->z_err = Z_ERRNO;
555 break;
557 s->stream.avail_out = AZ_BUFSIZE_WRITE;
559 s->in += s->stream.avail_in;
560 s->out += s->stream.avail_out;
561 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
562 s->in -= s->stream.avail_in;
563 s->out -= s->stream.avail_out;
564 if (s->z_err != Z_OK) break;
566 s->crc = crc32(s->crc, (const Bytef *)buf, len);
568 if (len > s->longest_row)
569 s->longest_row= len;
571 if (len < s->shortest_row || !(s->shortest_row))
572 s->shortest_row= len;
574 return (unsigned int)(len - s->stream.avail_in);
578 /* ===========================================================================
579 Flushes all pending output into the compressed file. The parameter
580 flush is as in the deflate() function.
582 int do_flush (azio_stream *s, int flush)
584 uInt len;
585 int done = 0;
586 my_off_t afterwrite_pos;
588 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
590 s->stream.avail_in = 0; /* should be zero already anyway */
592 for (;;)
594 len = AZ_BUFSIZE_WRITE - s->stream.avail_out;
596 if (len != 0)
598 s->check_point= my_tell(s->file, MYF(0));
599 if ((uInt)my_write(s->file, (uchar *)s->outbuf, len, MYF(0)) != len)
601 s->z_err = Z_ERRNO;
602 return Z_ERRNO;
604 s->stream.next_out = s->outbuf;
605 s->stream.avail_out = AZ_BUFSIZE_WRITE;
607 if (done) break;
608 s->out += s->stream.avail_out;
609 s->z_err = deflate(&(s->stream), flush);
610 s->out -= s->stream.avail_out;
612 /* Ignore the second of two consecutive flushes: */
613 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
615 /* deflate has finished flushing only when it hasn't used up
616 * all the available space in the output buffer:
618 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
620 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
623 if (flush == Z_FINISH)
624 s->dirty= AZ_STATE_CLEAN; /* Mark it clean, we should be good now */
625 else
626 s->dirty= AZ_STATE_SAVED; /* Mark it clean, we should be good now */
628 afterwrite_pos= my_tell(s->file, MYF(0));
629 write_header(s);
630 my_seek(s->file, afterwrite_pos, SEEK_SET, MYF(0));
632 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
635 int ZEXPORT azflush (s, flush)
636 azio_stream *s;
637 int flush;
639 int err;
641 if (s->mode == 'r')
643 unsigned char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
644 my_pread(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
645 MYF(0));
646 read_header(s, buffer); /* skip the .az header */
648 return Z_OK;
650 else
652 s->forced_flushes++;
653 err= do_flush(s, flush);
655 if (err) return err;
656 my_sync(s->file, MYF(0));
657 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
661 /* ===========================================================================
662 Rewinds input file.
664 int azrewind (s)
665 azio_stream *s;
667 if (s == NULL || s->mode != 'r') return -1;
669 s->z_err = Z_OK;
670 s->z_eof = 0;
671 s->back = EOF;
672 s->stream.avail_in = 0;
673 s->stream.next_in = (Bytef *)s->inbuf;
674 s->crc = crc32(0L, Z_NULL, 0);
675 if (!s->transparent) (void)inflateReset(&s->stream);
676 s->in = 0;
677 s->out = 0;
678 return my_seek(s->file, (int)s->start, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR;
681 /* ===========================================================================
682 Sets the starting position for the next azread or azwrite on the given
683 compressed file. The offset represents a number of bytes in the
684 azseek returns the resulting offset location as measured in bytes from
685 the beginning of the uncompressed stream, or -1 in case of error.
686 SEEK_END is not implemented, returns error.
687 In this version of the library, azseek can be extremely slow.
689 my_off_t azseek (s, offset, whence)
690 azio_stream *s;
691 my_off_t offset;
692 int whence;
695 if (s == NULL || whence == SEEK_END ||
696 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
697 return -1L;
700 if (s->mode == 'w')
702 if (whence == SEEK_SET)
703 offset -= s->in;
705 /* At this point, offset is the number of zero bytes to write. */
706 /* There was a zmemzero here if inbuf was null -Brian */
707 while (offset > 0)
709 uInt size = AZ_BUFSIZE_READ;
710 if (offset < AZ_BUFSIZE_READ) size = (uInt)offset;
712 size = azwrite(s, s->inbuf, size);
713 if (size == 0) return -1L;
715 offset -= size;
717 return s->in;
719 /* Rest of function is for reading only */
721 /* compute absolute position */
722 if (whence == SEEK_CUR) {
723 offset += s->out;
726 if (s->transparent) {
727 /* map to my_seek */
728 s->back = EOF;
729 s->stream.avail_in = 0;
730 s->stream.next_in = (Bytef *)s->inbuf;
731 if (my_seek(s->file, offset, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) return -1L;
733 s->in = s->out = offset;
734 return offset;
737 /* For a negative seek, rewind and use positive seek */
738 if (offset >= s->out) {
739 offset -= s->out;
740 } else if (azrewind(s)) {
741 return -1L;
743 /* offset is now the number of bytes to skip. */
745 if (offset && s->back != EOF) {
746 s->back = EOF;
747 s->out++;
748 offset--;
749 if (s->last) s->z_err = Z_STREAM_END;
751 while (offset > 0) {
752 int error;
753 unsigned int size = AZ_BUFSIZE_WRITE;
754 if (offset < AZ_BUFSIZE_WRITE) size = (int)offset;
756 size = azread(s, s->outbuf, size, &error);
757 if (error < 0) return -1L;
758 offset -= size;
760 return s->out;
763 /* ===========================================================================
764 Returns the starting position for the next azread or azwrite on the
765 given compressed file. This position represents a number of bytes in the
766 uncompressed data stream.
768 my_off_t ZEXPORT aztell (file)
769 azio_stream *file;
771 return azseek(file, 0L, SEEK_CUR);
775 /* ===========================================================================
776 Outputs a long in LSB order to the given file
778 void putLong (File file, uLong x)
780 int n;
781 uchar buffer[1];
783 for (n = 0; n < 4; n++)
785 buffer[0]= (int)(x & 0xff);
786 my_write(file, buffer, 1, MYF(0));
787 x >>= 8;
791 /* ===========================================================================
792 Reads a long in LSB order from the given azio_stream. Sets z_err in case
793 of error.
795 uLong getLong (azio_stream *s)
797 uLong x = (uLong)get_byte(s);
798 int c;
800 x += ((uLong)get_byte(s))<<8;
801 x += ((uLong)get_byte(s))<<16;
802 c = get_byte(s);
803 if (c == EOF) s->z_err = Z_DATA_ERROR;
804 x += ((uLong)c)<<24;
805 return x;
808 /* ===========================================================================
809 Flushes all pending output if necessary, closes the compressed file
810 and deallocates all the (de)compression state.
812 int azclose (azio_stream *s)
815 if (s == NULL) return Z_STREAM_ERROR;
817 if (s->file < 1) return Z_OK;
819 if (s->mode == 'w')
821 if (do_flush(s, Z_FINISH) != Z_OK)
822 return destroy(s);
824 putLong(s->file, s->crc);
825 putLong(s->file, (uLong)(s->in & 0xffffffff));
826 s->dirty= AZ_STATE_CLEAN;
827 s->check_point= my_tell(s->file, MYF(0));
828 write_header(s);
831 return destroy(s);
835 Though this was added to support MySQL's FRM file, anything can be
836 stored in this location.
838 int azwrite_frm(azio_stream *s, char *blob, unsigned int length)
840 if (s->mode == 'r')
841 return 1;
843 if (s->rows > 0)
844 return 1;
846 s->frm_start_pos= (uint) s->start;
847 s->frm_length= length;
848 s->start+= length;
850 my_pwrite(s->file, (uchar*) blob, s->frm_length, s->frm_start_pos, MYF(0));
852 write_header(s);
853 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
855 return 0;
858 int azread_frm(azio_stream *s, char *blob)
860 my_pread(s->file, (uchar*) blob, s->frm_length, s->frm_start_pos, MYF(0));
862 return 0;
867 Simple comment field
869 int azwrite_comment(azio_stream *s, char *blob, unsigned int length)
871 if (s->mode == 'r')
872 return 1;
874 if (s->rows > 0)
875 return 1;
877 s->comment_start_pos= (uint) s->start;
878 s->comment_length= length;
879 s->start+= length;
881 my_pwrite(s->file, (uchar*) blob, s->comment_length, s->comment_start_pos,
882 MYF(0));
884 write_header(s);
885 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
887 return 0;
890 int azread_comment(azio_stream *s, char *blob)
892 my_pread(s->file, (uchar*) blob, s->comment_length, s->comment_start_pos,
893 MYF(0));
895 return 0;