]> git.donarmstrong.com Git - samtools.git/blob - bgzf.c
* samtools-0.1.3-13 (r260)
[samtools.git] / bgzf.c
1 /*
2  * The Broad Institute
3  * SOFTWARE COPYRIGHT NOTICE AGREEMENT
4  * This software and its documentation are copyright 2008 by the
5  * Broad Institute/Massachusetts Institute of Technology. All rights are reserved.
6  *
7  * This software is supplied without any warranty or guaranteed support whatsoever.
8  * Neither the Broad Institute nor MIT can be responsible for its use, misuse,
9  * or functionality.
10  */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include "bgzf.h"
20
21 extern off_t ftello(FILE *stream);
22 extern int fseeko(FILE *stream, off_t offset, int whence);
23
24 typedef int8_t byte;
25
26 static const int DEFAULT_BLOCK_SIZE = 64 * 1024;
27 static const int MAX_BLOCK_SIZE = 64 * 1024;
28
29 static const int BLOCK_HEADER_LENGTH = 18;
30 static const int BLOCK_FOOTER_LENGTH = 8;
31
32 static const int GZIP_ID1 = 31;
33 static const int GZIP_ID2 = 139;
34 static const int CM_DEFLATE = 8;
35 static const int FLG_FEXTRA = 4;
36 static const int OS_UNKNOWN = 255;
37 static const int BGZF_ID1 = 66; // 'B'
38 static const int BGZF_ID2 = 67; // 'C'
39 static const int BGZF_LEN = 2;
40 static const int BGZF_XLEN = 6; // BGZF_LEN+4
41
42 static const int GZIP_WINDOW_BITS = -15; // no zlib header
43 static const int Z_DEFAULT_MEM_LEVEL = 8;
44
45
46 inline
47 void
48 packInt16(uint8_t* buffer, uint16_t value)
49 {
50     buffer[0] = value;
51     buffer[1] = value >> 8;
52 }
53
54 inline
55 int
56 unpackInt16(const uint8_t* buffer)
57 {
58     return (buffer[0] | (buffer[1] << 8));
59 }
60
61 inline
62 void
63 packInt32(uint8_t* buffer, uint32_t value)
64 {
65     buffer[0] = value;
66     buffer[1] = value >> 8;
67     buffer[2] = value >> 16;
68     buffer[3] = value >> 24;
69 }
70
71 inline
72 int
73 min(int x, int y)
74 {
75     return (x < y) ? x : y;
76 }
77
78 static
79 void
80 report_error(BGZF* fp, const char* message) {
81     fp->error = message;
82 }
83
84 static
85 BGZF*
86 open_read(int fd)
87 {
88     FILE* file = fdopen(fd, "r");
89     BGZF* fp;
90         if (file == 0) return 0;
91         fp = malloc(sizeof(BGZF));
92     fp->file_descriptor = fd;
93     fp->open_mode = 'r';
94     fp->owned_file = 0;
95     fp->file = file;
96     fp->uncompressed_block_size = MAX_BLOCK_SIZE;
97     fp->uncompressed_block = malloc(MAX_BLOCK_SIZE);
98     fp->compressed_block_size = MAX_BLOCK_SIZE;
99     fp->compressed_block = malloc(MAX_BLOCK_SIZE);
100     fp->block_address = 0;
101     fp->block_offset = 0;
102     fp->block_length = 0;
103     fp->error = NULL;
104     return fp;
105 }
106
107 static
108 BGZF*
109 open_write(int fd)
110 {
111     FILE* file = fdopen(fd, "w");
112     BGZF* fp;
113         if (file == 0) return 0;
114         fp = malloc(sizeof(BGZF));
115     fp->file_descriptor = fd;
116     fp->open_mode = 'w';
117     fp->owned_file = 0;
118     fp->file = file;
119     fp->uncompressed_block_size = DEFAULT_BLOCK_SIZE;
120     fp->uncompressed_block = NULL;
121     fp->compressed_block_size = MAX_BLOCK_SIZE;
122     fp->compressed_block = malloc(MAX_BLOCK_SIZE);
123     fp->block_address = 0;
124     fp->block_offset = 0;
125     fp->block_length = 0;
126     fp->error = NULL;
127     return fp;
128 }
129
130 BGZF*
131 bgzf_open(const char* __restrict path, const char* __restrict mode)
132 {
133     BGZF* fp = NULL;
134     if (strcasecmp(mode, "r") == 0) {
135         int oflag = O_RDONLY;
136         int fd = open(path, oflag);
137         fp = open_read(fd);
138     } else if (strcasecmp(mode, "w") == 0) {
139         int oflag = O_WRONLY | O_CREAT | O_TRUNC;
140         int fd = open(path, oflag, 0644);
141         fp = open_write(fd);
142     }
143     if (fp != NULL) {
144         fp->owned_file = 1;
145     }
146     return fp;
147 }
148
149 BGZF*
150 bgzf_fdopen(int fd, const char * __restrict mode)
151 {
152     if (strcasecmp(mode, "r") == 0) {
153         return open_read(fd);
154     } else if (strcasecmp(mode, "w") == 0) {
155         return open_write(fd);
156     } else {
157         return NULL;
158     }
159 }
160
161 static
162 int
163 deflate_block(BGZF* fp, int block_length)
164 {
165     // Deflate the block in fp->uncompressed_block into fp->compressed_block.
166     // Also adds an extra field that stores the compressed block length.
167
168     byte* buffer = fp->compressed_block;
169     int buffer_size = fp->compressed_block_size;
170
171     // Init gzip header
172     buffer[0] = GZIP_ID1;
173     buffer[1] = GZIP_ID2;
174     buffer[2] = CM_DEFLATE;
175     buffer[3] = FLG_FEXTRA;
176     buffer[4] = 0; // mtime
177     buffer[5] = 0;
178     buffer[6] = 0;
179     buffer[7] = 0;
180     buffer[8] = 0;
181     buffer[9] = OS_UNKNOWN;
182     buffer[10] = BGZF_XLEN;
183     buffer[11] = 0;
184     buffer[12] = BGZF_ID1;
185     buffer[13] = BGZF_ID2;
186     buffer[14] = BGZF_LEN;
187     buffer[15] = 0;
188     buffer[16] = 0; // placeholder for block length
189     buffer[17] = 0;
190
191     // loop to retry for blocks that do not compress enough
192     int input_length = block_length;
193     int compressed_length = 0;
194     while (1) {
195
196         z_stream zs;
197         zs.zalloc = NULL;
198         zs.zfree = NULL;
199         zs.next_in = fp->uncompressed_block;
200         zs.avail_in = input_length;
201         zs.next_out = (void*)&buffer[BLOCK_HEADER_LENGTH];
202         zs.avail_out = buffer_size - BLOCK_HEADER_LENGTH - BLOCK_FOOTER_LENGTH;
203
204         int status = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
205                                   GZIP_WINDOW_BITS, Z_DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
206         if (status != Z_OK) {
207             report_error(fp, "deflate init failed");
208             return -1;
209         }
210         status = deflate(&zs, Z_FINISH);
211         if (status != Z_STREAM_END) {
212             deflateEnd(&zs);
213             if (status == Z_OK) {
214                 // Not enough space in buffer.
215                 // Can happen in the rare case the input doesn't compress enough.
216                 // Reduce the amount of input until it fits.
217                 input_length -= 1024;
218                 if (input_length <= 0) {
219                     // should never happen
220                     report_error(fp, "input reduction failed");
221                     return -1;
222                 }
223                 continue;
224             }
225             report_error(fp, "deflate failed");
226             return -1;
227         }
228         status = deflateEnd(&zs);
229         if (status != Z_OK) {
230             report_error(fp, "deflate end failed");
231             return -1;
232         }
233         compressed_length = zs.total_out;
234         compressed_length += BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH;
235         if (compressed_length > MAX_BLOCK_SIZE) {
236             // should never happen
237             report_error(fp, "deflate overflow");
238             return -1;
239         }
240         break;
241     }
242
243     packInt16((uint8_t*)&buffer[16], compressed_length-1);
244     uint32_t crc = crc32(0L, NULL, 0L);
245     crc = crc32(crc, fp->uncompressed_block, input_length);
246     packInt32((uint8_t*)&buffer[compressed_length-8], crc);
247     packInt32((uint8_t*)&buffer[compressed_length-4], input_length);
248
249     int remaining = block_length - input_length;
250     if (remaining > 0) {
251         if (remaining > input_length) {
252             // should never happen (check so we can use memcpy)
253             report_error(fp, "remainder too large");
254             return -1;
255         }
256         memcpy(fp->uncompressed_block,
257                fp->uncompressed_block + input_length,
258                remaining);
259     }
260     fp->block_offset = remaining;
261     return compressed_length;
262 }
263
264 static
265 int
266 inflate_block(BGZF* fp, int block_length)
267 {
268     // Inflate the block in fp->compressed_block into fp->uncompressed_block
269
270     z_stream zs;
271     zs.zalloc = NULL;
272     zs.zfree = NULL;
273     zs.next_in = fp->compressed_block + 18;
274     zs.avail_in = block_length - 16;
275     zs.next_out = fp->uncompressed_block;
276     zs.avail_out = fp->uncompressed_block_size;
277
278     int status = inflateInit2(&zs, GZIP_WINDOW_BITS);
279     if (status != Z_OK) {
280         report_error(fp, "inflate init failed");
281         return -1;
282     }
283     status = inflate(&zs, Z_FINISH);
284     if (status != Z_STREAM_END) {
285         inflateEnd(&zs);
286         report_error(fp, "inflate failed");
287         return -1;
288     }
289     status = inflateEnd(&zs);
290     if (status != Z_OK) {
291         report_error(fp, "inflate failed");
292         return -1;
293     }
294     return zs.total_out;
295 }
296
297 static
298 int
299 check_header(const byte* header)
300 {
301     return (header[0] == GZIP_ID1 &&
302             header[1] == (byte) GZIP_ID2 &&
303             header[2] == Z_DEFLATED &&
304             (header[3] & FLG_FEXTRA) != 0 &&
305             unpackInt16((uint8_t*)&header[10]) == BGZF_XLEN &&
306             header[12] == BGZF_ID1 &&
307             header[13] == BGZF_ID2 &&
308             unpackInt16((uint8_t*)&header[14]) == BGZF_LEN);
309 }
310
311 static
312 int
313 read_block(BGZF* fp)
314 {
315     byte header[BLOCK_HEADER_LENGTH];
316     int64_t block_address = ftello(fp->file);
317     int count = fread(header, 1, sizeof(header), fp->file);
318     if (count == 0) {
319         fp->block_length = 0;
320         return 0;
321     }
322     if (count != sizeof(header)) {
323         report_error(fp, "read failed");
324         return -1;
325     }
326     if (!check_header(header)) {
327         report_error(fp, "invalid block header");
328         return -1;
329     }
330     int block_length = unpackInt16((uint8_t*)&header[16]) + 1;
331     byte* compressed_block = (byte*) fp->compressed_block;
332     memcpy(compressed_block, header, BLOCK_HEADER_LENGTH);
333     int remaining = block_length - BLOCK_HEADER_LENGTH;
334     count = fread(&compressed_block[BLOCK_HEADER_LENGTH], 1, remaining, fp->file);
335     if (count != remaining) {
336         report_error(fp, "read failed");
337         return -1;
338     }
339     count = inflate_block(fp, block_length);
340     if (count < 0) {
341         return -1;
342     }
343     if (fp->block_length != 0) {
344         // Do not reset offset if this read follows a seek.
345         fp->block_offset = 0;
346     }
347     fp->block_address = block_address;
348     fp->block_length = count;
349     return 0;
350 }
351
352 int
353 bgzf_read(BGZF* fp, void* data, int length)
354 {
355     if (length <= 0) {
356         return 0;
357     }
358     if (fp->open_mode != 'r') {
359         report_error(fp, "file not open for reading");
360         return -1;
361     }
362
363     int bytes_read = 0;
364     byte* output = data;
365     while (bytes_read < length) {
366         int available = fp->block_length - fp->block_offset;
367         if (available <= 0) {
368             if (read_block(fp) != 0) {
369                 return -1;
370             }
371             available = fp->block_length - fp->block_offset;
372             if (available <= 0) {
373                 break;
374             }
375         }
376         int copy_length = min(length-bytes_read, available);
377         byte* buffer = fp->uncompressed_block;
378         memcpy(output, buffer + fp->block_offset, copy_length);
379         fp->block_offset += copy_length;
380         output += copy_length;
381         bytes_read += copy_length;
382     }
383     if (fp->block_offset == fp->block_length) {
384         fp->block_address = ftello(fp->file);
385         fp->block_offset = 0;
386         fp->block_length = 0;
387     }
388     return bytes_read;
389 }
390
391 static
392 int
393 flush_block(BGZF* fp)
394 {
395     while (fp->block_offset > 0) {
396         int block_length = deflate_block(fp, fp->block_offset);
397         if (block_length < 0) {
398             return -1;
399         }
400         int count = fwrite(fp->compressed_block, 1, block_length, fp->file);
401         if (count != block_length) {
402             report_error(fp, "write failed");
403             return -1;
404         }
405         fp->block_address += block_length;
406     }
407     return 0;
408 }
409
410 int
411 bgzf_write(BGZF* fp, const void* data, int length)
412 {
413     if (fp->open_mode != 'w') {
414         report_error(fp, "file not open for writing");
415         return -1;
416     }
417
418     if (fp->uncompressed_block == NULL) {
419         fp->uncompressed_block = malloc(fp->uncompressed_block_size);
420     }
421
422     const byte* input = data;
423     int block_length = fp->uncompressed_block_size;
424     int bytes_written = 0;
425     while (bytes_written < length) {
426         int copy_length = min(block_length - fp->block_offset, length - bytes_written);
427         byte* buffer = fp->uncompressed_block;
428         memcpy(buffer + fp->block_offset, input, copy_length);
429         fp->block_offset += copy_length;
430         input += copy_length;
431         bytes_written += copy_length;
432         if (fp->block_offset == block_length) {
433             if (flush_block(fp) != 0) {
434                 break;
435             }
436         }
437     }
438     return bytes_written;
439 }
440
441 int
442 bgzf_close(BGZF* fp)
443 {
444     if (fp->open_mode == 'w') {
445         if (flush_block(fp) != 0) {
446             return -1;
447         }
448         if (fflush(fp->file) != 0) {
449             report_error(fp, "flush failed");
450             return -1;
451         }
452     }
453     if (fp->owned_file) {
454         if (fclose(fp->file) != 0) {
455             return -1;
456         }
457     }
458     free(fp->uncompressed_block);
459     free(fp->compressed_block);
460     free(fp);
461     return 0;
462 }
463
464 int64_t
465 bgzf_tell(BGZF* fp)
466 {
467     return ((fp->block_address << 16) | (fp->block_offset & 0xFFFF));
468 }
469
470 int64_t
471 bgzf_seek(BGZF* fp, int64_t pos, int where)
472 {
473     if (fp->open_mode != 'r') {
474         report_error(fp, "file not open for read");
475         return -1;
476     }
477     if (where != SEEK_SET) {
478         report_error(fp, "unimplemented seek option");
479         return -1;
480     }
481     int block_offset = pos & 0xFFFF;
482     int64_t block_address = (pos >> 16) & 0xFFFFFFFFFFFFLL;
483     if (fseeko(fp->file, block_address, SEEK_SET) != 0) {
484         report_error(fp, "seek failed");
485         return -1;
486     }
487     fp->block_length = 0;  // indicates current block is not loaded
488     fp->block_address = block_address;
489     fp->block_offset = block_offset;
490     return 0;
491 }
492