/src/htslib/cram/cram_io.h
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 2012-2020 Genome Research Ltd. |
3 | | Author: James Bonfield <jkb@sanger.ac.uk> |
4 | | |
5 | | Redistribution and use in source and binary forms, with or without |
6 | | modification, are permitted provided that the following conditions are met: |
7 | | |
8 | | 1. Redistributions of source code must retain the above copyright notice, |
9 | | this list of conditions and the following disclaimer. |
10 | | |
11 | | 2. Redistributions in binary form must reproduce the above copyright notice, |
12 | | this list of conditions and the following disclaimer in the documentation |
13 | | and/or other materials provided with the distribution. |
14 | | |
15 | | 3. Neither the names Genome Research Ltd and Wellcome Trust Sanger |
16 | | Institute nor the names of its contributors may be used to endorse or promote |
17 | | products derived from this software without specific prior written permission. |
18 | | |
19 | | THIS SOFTWARE IS PROVIDED BY GENOME RESEARCH LTD AND CONTRIBUTORS "AS IS" AND |
20 | | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
21 | | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
22 | | DISCLAIMED. IN NO EVENT SHALL GENOME RESEARCH LTD OR CONTRIBUTORS BE LIABLE |
23 | | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
25 | | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
26 | | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
27 | | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
28 | | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 | | */ |
30 | | |
31 | | /*! \file |
32 | | * Include cram.h instead. |
33 | | * |
34 | | * This is an internal part of the CRAM system and is automatically included |
35 | | * when you #include cram.h. |
36 | | * |
37 | | * Implements the low level CRAM I/O primitives. |
38 | | * This includes basic data types such as byte, int, ITF-8, |
39 | | * maps, bitwise I/O, etc. |
40 | | */ |
41 | | |
42 | | #ifndef CRAM_IO_H |
43 | | #define CRAM_IO_H |
44 | | |
45 | | #include <stdint.h> |
46 | | |
47 | | #include "misc.h" |
48 | | |
49 | | #ifdef __cplusplus |
50 | | extern "C" { |
51 | | #endif |
52 | | |
53 | | /**@{ ---------------------------------------------------------------------- |
54 | | * ITF8 encoding and decoding. |
55 | | * |
56 | | * Also see the itf8_get and itf8_put macros. |
57 | | */ |
58 | | |
59 | | /*! INTERNAL: Converts two characters into an integer for use in switch{} */ |
60 | 644k | #define CRAM_KEY(a,b) ((((unsigned char) a)<<8)|(((unsigned char) b))) |
61 | | |
62 | | /*! Reads an integer in ITF-8 encoding from 'fd' and stores it in |
63 | | * *val. |
64 | | * |
65 | | * @return |
66 | | * Returns the number of bytes read on success; |
67 | | * -1 on failure |
68 | | */ |
69 | | int itf8_decode(cram_fd *fd, int32_t *val); |
70 | | |
71 | | extern const int itf8_bytes[16]; |
72 | | extern const int ltf8_bytes[256]; |
73 | | |
74 | | /*! Pushes a value in ITF8 format onto the end of a block. |
75 | | * |
76 | | * This shouldn't be used for high-volume data as it is not the fastest |
77 | | * method. |
78 | | * |
79 | | * @return |
80 | | * Returns the number of bytes written |
81 | | */ |
82 | | int itf8_put_blk(cram_block *blk, int32_t val); |
83 | | int ltf8_put_blk(cram_block *blk, int64_t val); |
84 | | |
85 | | /*! Pulls a literal 32-bit value from a block. |
86 | | * |
87 | | * @returns the number of bytes decoded; |
88 | | * -1 on failure. |
89 | | */ |
90 | | int int32_get_blk(cram_block *b, int32_t *val); |
91 | | |
92 | | /*! Pushes a literal 32-bit value onto the end of a block. |
93 | | * |
94 | | * @return |
95 | | * Returns 0 on success; |
96 | | * -1 on failure. |
97 | | */ |
98 | | int int32_put_blk(cram_block *blk, int32_t val); |
99 | | |
100 | | |
101 | | /**@}*/ |
102 | | /**@{ ---------------------------------------------------------------------- |
103 | | * CRAM blocks - the dynamically growable data block. We have code to |
104 | | * create, update, (un)compress and read/write. |
105 | | * |
106 | | * These are derived from the deflate_interlaced.c blocks, but with the |
107 | | * CRAM extension of content types and IDs. |
108 | | */ |
109 | | |
110 | | /*! Allocates a new cram_block structure with a specified content_type and |
111 | | * id. |
112 | | * |
113 | | * @return |
114 | | * Returns block pointer on success; |
115 | | * NULL on failure |
116 | | */ |
117 | | cram_block *cram_new_block(enum cram_content_type content_type, |
118 | | int content_id); |
119 | | |
120 | | /*! Reads a block from a cram file. |
121 | | * |
122 | | * @return |
123 | | * Returns cram_block pointer on success; |
124 | | * NULL on failure |
125 | | */ |
126 | | cram_block *cram_read_block(cram_fd *fd); |
127 | | |
128 | | /*! Writes a CRAM block. |
129 | | * |
130 | | * @return |
131 | | * Returns 0 on success; |
132 | | * -1 on failure |
133 | | */ |
134 | | int cram_write_block(cram_fd *fd, cram_block *b); |
135 | | |
136 | | /*! Frees a CRAM block, deallocating internal data too. |
137 | | */ |
138 | | void cram_free_block(cram_block *b); |
139 | | |
140 | | /*! Uncompresses a CRAM block, if compressed. |
141 | | * |
142 | | * @return |
143 | | * Returns 0 on success; |
144 | | * -1 on failure |
145 | | */ |
146 | | int cram_uncompress_block(cram_block *b); |
147 | | |
148 | | /*! Compresses a block. |
149 | | * |
150 | | * Compresses a block using one of two different zlib strategies. If we only |
151 | | * want one choice set strat2 to be -1. |
152 | | * |
153 | | * The logic here is that sometimes Z_RLE does a better job than Z_FILTERED |
154 | | * or Z_DEFAULT_STRATEGY on quality data. If so, we'd rather use it as it is |
155 | | * significantly faster. |
156 | | * |
157 | | * @return |
158 | | * Returns 0 on success; |
159 | | * -1 on failure |
160 | | */ |
161 | | int cram_compress_block(cram_fd *fd, cram_block *b, cram_metrics *metrics, |
162 | | int method, int level); |
163 | | int cram_compress_block2(cram_fd *fd, cram_slice *s, |
164 | | cram_block *b, cram_metrics *metrics, |
165 | | int method, int level); |
166 | | |
167 | | cram_metrics *cram_new_metrics(void); |
168 | | char *cram_block_method2str(enum cram_block_method_int m); |
169 | | char *cram_content_type2str(enum cram_content_type t); |
170 | | |
171 | | /* |
172 | | * Find an external block by its content_id |
173 | | */ |
174 | | |
175 | 39 | static inline cram_block *cram_get_block_by_id(cram_slice *slice, int id) { |
176 | | //fprintf(stderr, "%d\t%p\n", id, slice->block_by_id); |
177 | 39 | uint32_t v = id; |
178 | 39 | if (slice->block_by_id && v < 256) { |
179 | 24 | return slice->block_by_id[v]; |
180 | 24 | } else { |
181 | 15 | v = 256 + v % 251; |
182 | 15 | if (slice->block_by_id && |
183 | 15 | slice->block_by_id[v] && |
184 | 0 | slice->block_by_id[v]->content_id == id) |
185 | 0 | return slice->block_by_id[v]; |
186 | | |
187 | | // Otherwise a linear search in case of collision |
188 | 15 | int i; |
189 | 45 | for (i = 0; i < slice->hdr->num_blocks; i++) { |
190 | 30 | cram_block *b = slice->block[i]; |
191 | 30 | if (b && b->content_type == EXTERNAL && b->content_id == id) |
192 | 0 | return b; |
193 | 30 | } |
194 | 15 | } |
195 | 15 | return NULL; |
196 | 39 | } Unexecuted instantiation: hts.c:cram_get_block_by_id Unexecuted instantiation: sam.c:cram_get_block_by_id cram_decode.c:cram_get_block_by_id Line | Count | Source | 175 | 39 | static inline cram_block *cram_get_block_by_id(cram_slice *slice, int id) { | 176 | | //fprintf(stderr, "%d\t%p\n", id, slice->block_by_id); | 177 | 39 | uint32_t v = id; | 178 | 39 | if (slice->block_by_id && v < 256) { | 179 | 24 | return slice->block_by_id[v]; | 180 | 24 | } else { | 181 | 15 | v = 256 + v % 251; | 182 | 15 | if (slice->block_by_id && | 183 | 15 | slice->block_by_id[v] && | 184 | 0 | slice->block_by_id[v]->content_id == id) | 185 | 0 | return slice->block_by_id[v]; | 186 | | | 187 | | // Otherwise a linear search in case of collision | 188 | 15 | int i; | 189 | 45 | for (i = 0; i < slice->hdr->num_blocks; i++) { | 190 | 30 | cram_block *b = slice->block[i]; | 191 | 30 | if (b && b->content_type == EXTERNAL && b->content_id == id) | 192 | 0 | return b; | 193 | 30 | } | 194 | 15 | } | 195 | 15 | return NULL; | 196 | 39 | } |
Unexecuted instantiation: cram_encode.c:cram_get_block_by_id Unexecuted instantiation: cram_index.c:cram_get_block_by_id Unexecuted instantiation: cram_io.c:cram_get_block_by_id Unexecuted instantiation: cram_stats.c:cram_get_block_by_id Unexecuted instantiation: cram_codecs.c:cram_get_block_by_id |
197 | | |
198 | | /* --- Accessor macros for manipulating blocks on a byte by byte basis --- */ |
199 | | |
200 | | /* Block size and data pointer. */ |
201 | 172M | #define BLOCK_SIZE(b) ((b)->byte) |
202 | 18.8M | #define BLOCK_DATA(b) ((b)->data) |
203 | | |
204 | | /* Returns the address one past the end of the block */ |
205 | 52.2M | #define BLOCK_END(b) (&(b)->data[(b)->byte]) |
206 | | |
207 | | /* Make block exactly 'l' bytes long */ |
208 | 70.4M | static inline int block_resize_exact(cram_block *b, size_t len) { |
209 | 70.4M | unsigned char *tmp = realloc(b->data, len); |
210 | 70.4M | if (!tmp) |
211 | 0 | return -1; |
212 | 70.4M | b->alloc = len; |
213 | 70.4M | b->data = tmp; |
214 | 70.4M | return 0; |
215 | 70.4M | } Unexecuted instantiation: hts.c:block_resize_exact Unexecuted instantiation: sam.c:block_resize_exact cram_decode.c:block_resize_exact Line | Count | Source | 208 | 552 | static inline int block_resize_exact(cram_block *b, size_t len) { | 209 | 552 | unsigned char *tmp = realloc(b->data, len); | 210 | 552 | if (!tmp) | 211 | 0 | return -1; | 212 | 552 | b->alloc = len; | 213 | 552 | b->data = tmp; | 214 | 552 | return 0; | 215 | 552 | } |
cram_encode.c:block_resize_exact Line | Count | Source | 208 | 47.5M | static inline int block_resize_exact(cram_block *b, size_t len) { | 209 | 47.5M | unsigned char *tmp = realloc(b->data, len); | 210 | 47.5M | if (!tmp) | 211 | 0 | return -1; | 212 | 47.5M | b->alloc = len; | 213 | 47.5M | b->data = tmp; | 214 | 47.5M | return 0; | 215 | 47.5M | } |
Unexecuted instantiation: cram_index.c:block_resize_exact cram_io.c:block_resize_exact Line | Count | Source | 208 | 20.9M | static inline int block_resize_exact(cram_block *b, size_t len) { | 209 | 20.9M | unsigned char *tmp = realloc(b->data, len); | 210 | 20.9M | if (!tmp) | 211 | 0 | return -1; | 212 | 20.9M | b->alloc = len; | 213 | 20.9M | b->data = tmp; | 214 | 20.9M | return 0; | 215 | 20.9M | } |
Unexecuted instantiation: cram_stats.c:block_resize_exact cram_codecs.c:block_resize_exact Line | Count | Source | 208 | 1.92M | static inline int block_resize_exact(cram_block *b, size_t len) { | 209 | 1.92M | unsigned char *tmp = realloc(b->data, len); | 210 | 1.92M | if (!tmp) | 211 | 0 | return -1; | 212 | 1.92M | b->alloc = len; | 213 | 1.92M | b->data = tmp; | 214 | 1.92M | return 0; | 215 | 1.92M | } |
|
216 | | |
217 | | /* Request block to be at least 'l' bytes long */ |
218 | 71.9M | static inline int block_resize(cram_block *b, size_t len) { |
219 | 71.9M | if (b->alloc > len) |
220 | 1.52M | return 0; |
221 | | |
222 | 70.4M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
223 | | // Removal of extra padding causes many more reallocs, but detects |
224 | | // more buffer overruns. |
225 | 70.4M | return block_resize_exact(b, len?len:1); |
226 | 0 | #endif |
227 | | |
228 | 0 | size_t alloc = b->alloc+800; |
229 | 0 | alloc = MAX(alloc + (alloc>>2), len); |
230 | 0 | return block_resize_exact(b, alloc); |
231 | 71.9M | } Unexecuted instantiation: hts.c:block_resize Unexecuted instantiation: sam.c:block_resize cram_decode.c:block_resize Line | Count | Source | 218 | 516 | static inline int block_resize(cram_block *b, size_t len) { | 219 | 516 | if (b->alloc > len) | 220 | 0 | return 0; | 221 | | | 222 | 516 | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 223 | | // Removal of extra padding causes many more reallocs, but detects | 224 | | // more buffer overruns. | 225 | 516 | return block_resize_exact(b, len?len:1); | 226 | 0 | #endif | 227 | | | 228 | 0 | size_t alloc = b->alloc+800; | 229 | 0 | alloc = MAX(alloc + (alloc>>2), len); | 230 | 0 | return block_resize_exact(b, alloc); | 231 | 516 | } |
cram_encode.c:block_resize Line | Count | Source | 218 | 48.4M | static inline int block_resize(cram_block *b, size_t len) { | 219 | 48.4M | if (b->alloc > len) | 220 | 869k | return 0; | 221 | | | 222 | 47.5M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 223 | | // Removal of extra padding causes many more reallocs, but detects | 224 | | // more buffer overruns. | 225 | 47.5M | return block_resize_exact(b, len?len:1); | 226 | 0 | #endif | 227 | | | 228 | 0 | size_t alloc = b->alloc+800; | 229 | 0 | alloc = MAX(alloc + (alloc>>2), len); | 230 | 0 | return block_resize_exact(b, alloc); | 231 | 48.4M | } |
Unexecuted instantiation: cram_index.c:block_resize Line | Count | Source | 218 | 21.2M | static inline int block_resize(cram_block *b, size_t len) { | 219 | 21.2M | if (b->alloc > len) | 220 | 347k | return 0; | 221 | | | 222 | 20.9M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 223 | | // Removal of extra padding causes many more reallocs, but detects | 224 | | // more buffer overruns. | 225 | 20.9M | return block_resize_exact(b, len?len:1); | 226 | 0 | #endif | 227 | | | 228 | 0 | size_t alloc = b->alloc+800; | 229 | 0 | alloc = MAX(alloc + (alloc>>2), len); | 230 | 0 | return block_resize_exact(b, alloc); | 231 | 21.2M | } |
Unexecuted instantiation: cram_stats.c:block_resize cram_codecs.c:block_resize Line | Count | Source | 218 | 2.23M | static inline int block_resize(cram_block *b, size_t len) { | 219 | 2.23M | if (b->alloc > len) | 220 | 308k | return 0; | 221 | | | 222 | 1.92M | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION | 223 | | // Removal of extra padding causes many more reallocs, but detects | 224 | | // more buffer overruns. | 225 | 1.92M | return block_resize_exact(b, len?len:1); | 226 | 0 | #endif | 227 | | | 228 | 0 | size_t alloc = b->alloc+800; | 229 | 0 | alloc = MAX(alloc + (alloc>>2), len); | 230 | 0 | return block_resize_exact(b, alloc); | 231 | 2.23M | } |
|
232 | | |
233 | | |
234 | | /* Ensure the block can hold at least another 'l' bytes */ |
235 | 71.9M | static inline int block_grow(cram_block *b, size_t len) { |
236 | 71.9M | return block_resize(b, BLOCK_SIZE(b) + len); |
237 | 71.9M | } Unexecuted instantiation: hts.c:block_grow Unexecuted instantiation: sam.c:block_grow Line | Count | Source | 235 | 516 | static inline int block_grow(cram_block *b, size_t len) { | 236 | 516 | return block_resize(b, BLOCK_SIZE(b) + len); | 237 | 516 | } |
Line | Count | Source | 235 | 48.4M | static inline int block_grow(cram_block *b, size_t len) { | 236 | 48.4M | return block_resize(b, BLOCK_SIZE(b) + len); | 237 | 48.4M | } |
Unexecuted instantiation: cram_index.c:block_grow Line | Count | Source | 235 | 21.2M | static inline int block_grow(cram_block *b, size_t len) { | 236 | 21.2M | return block_resize(b, BLOCK_SIZE(b) + len); | 237 | 21.2M | } |
Unexecuted instantiation: cram_stats.c:block_grow Line | Count | Source | 235 | 2.23M | static inline int block_grow(cram_block *b, size_t len) { | 236 | 2.23M | return block_resize(b, BLOCK_SIZE(b) + len); | 237 | 2.23M | } |
|
238 | | |
239 | | /* Append string 's' of length 'l'. */ |
240 | 33.4M | static inline int block_append(cram_block *b, const void *s, size_t len) { |
241 | 33.4M | if (block_grow(b, len) < 0) |
242 | 0 | return -1; |
243 | | |
244 | 33.4M | if (len) { |
245 | 33.4M | memcpy(BLOCK_END(b), s, len); |
246 | 33.4M | BLOCK_SIZE(b) += len; |
247 | 33.4M | } |
248 | | |
249 | 33.4M | return 0; |
250 | 33.4M | } Unexecuted instantiation: hts.c:block_append Unexecuted instantiation: sam.c:block_append cram_decode.c:block_append Line | Count | Source | 240 | 306 | static inline int block_append(cram_block *b, const void *s, size_t len) { | 241 | 306 | if (block_grow(b, len) < 0) | 242 | 0 | return -1; | 243 | | | 244 | 306 | if (len) { | 245 | 306 | memcpy(BLOCK_END(b), s, len); | 246 | 306 | BLOCK_SIZE(b) += len; | 247 | 306 | } | 248 | | | 249 | 306 | return 0; | 250 | 306 | } |
cram_encode.c:block_append Line | Count | Source | 240 | 10.0M | static inline int block_append(cram_block *b, const void *s, size_t len) { | 241 | 10.0M | if (block_grow(b, len) < 0) | 242 | 0 | return -1; | 243 | | | 244 | 10.0M | if (len) { | 245 | 10.0M | memcpy(BLOCK_END(b), s, len); | 246 | 10.0M | BLOCK_SIZE(b) += len; | 247 | 10.0M | } | 248 | | | 249 | 10.0M | return 0; | 250 | 10.0M | } |
Unexecuted instantiation: cram_index.c:block_append Line | Count | Source | 240 | 21.2M | static inline int block_append(cram_block *b, const void *s, size_t len) { | 241 | 21.2M | if (block_grow(b, len) < 0) | 242 | 0 | return -1; | 243 | | | 244 | 21.2M | if (len) { | 245 | 21.2M | memcpy(BLOCK_END(b), s, len); | 246 | 21.2M | BLOCK_SIZE(b) += len; | 247 | 21.2M | } | 248 | | | 249 | 21.2M | return 0; | 250 | 21.2M | } |
Unexecuted instantiation: cram_stats.c:block_append cram_codecs.c:block_append Line | Count | Source | 240 | 2.14M | static inline int block_append(cram_block *b, const void *s, size_t len) { | 241 | 2.14M | if (block_grow(b, len) < 0) | 242 | 0 | return -1; | 243 | | | 244 | 2.14M | if (len) { | 245 | 2.14M | memcpy(BLOCK_END(b), s, len); | 246 | 2.14M | BLOCK_SIZE(b) += len; | 247 | 2.14M | } | 248 | | | 249 | 2.14M | return 0; | 250 | 2.14M | } |
|
251 | | |
252 | | /* Append as single character 'c' */ |
253 | 10.2M | static inline int block_append_char(cram_block *b, char c) { |
254 | 10.2M | if (block_grow(b, 1) < 0) |
255 | 0 | return -1; |
256 | | |
257 | 10.2M | b->data[b->byte++] = c; |
258 | 10.2M | return 0; |
259 | 10.2M | } Unexecuted instantiation: hts.c:block_append_char Unexecuted instantiation: sam.c:block_append_char cram_decode.c:block_append_char Line | Count | Source | 253 | 210 | static inline int block_append_char(cram_block *b, char c) { | 254 | 210 | if (block_grow(b, 1) < 0) | 255 | 0 | return -1; | 256 | | | 257 | 210 | b->data[b->byte++] = c; | 258 | 210 | return 0; | 259 | 210 | } |
cram_encode.c:block_append_char Line | Count | Source | 253 | 10.1M | static inline int block_append_char(cram_block *b, char c) { | 254 | 10.1M | if (block_grow(b, 1) < 0) | 255 | 0 | return -1; | 256 | | | 257 | 10.1M | b->data[b->byte++] = c; | 258 | 10.1M | return 0; | 259 | 10.1M | } |
Unexecuted instantiation: cram_index.c:block_append_char Unexecuted instantiation: cram_io.c:block_append_char Unexecuted instantiation: cram_stats.c:block_append_char cram_codecs.c:block_append_char Line | Count | Source | 253 | 95.0k | static inline int block_append_char(cram_block *b, char c) { | 254 | 95.0k | if (block_grow(b, 1) < 0) | 255 | 0 | return -1; | 256 | | | 257 | 95.0k | b->data[b->byte++] = c; | 258 | 95.0k | return 0; | 259 | 95.0k | } |
|
260 | | |
261 | | /* Append a single unsigned integer */ |
262 | | static inline unsigned char *append_uint32(unsigned char *cp, uint32_t i); |
263 | 0 | static inline int block_append_uint(cram_block *b, unsigned int i) { |
264 | 0 | if (block_grow(b, 11) < 0) |
265 | 0 | return -1; |
266 | | |
267 | 0 | unsigned char *cp = &b->data[b->byte]; |
268 | 0 | b->byte += append_uint32(cp, i) - cp; |
269 | 0 | return 0; |
270 | 0 | } Unexecuted instantiation: hts.c:block_append_uint Unexecuted instantiation: sam.c:block_append_uint Unexecuted instantiation: cram_decode.c:block_append_uint Unexecuted instantiation: cram_encode.c:block_append_uint Unexecuted instantiation: cram_index.c:block_append_uint Unexecuted instantiation: cram_io.c:block_append_uint Unexecuted instantiation: cram_stats.c:block_append_uint Unexecuted instantiation: cram_codecs.c:block_append_uint |
271 | | |
272 | | // Versions of above with built in goto block_err calls. |
273 | 36 | #define BLOCK_RESIZE_EXACT(b,l) if (block_resize_exact((b),(l))<0) goto block_err |
274 | 10.2k | #define BLOCK_RESIZE(b,l) if (block_resize((b),(l)) <0) goto block_err |
275 | 28.2M | #define BLOCK_GROW(b,l) if (block_grow((b),(l)) <0) goto block_err |
276 | 33.4M | #define BLOCK_APPEND(b,s,l) if (block_append((b),(s),(l)) <0) goto block_err |
277 | 10.2M | #define BLOCK_APPEND_CHAR(b,c) if (block_append_char((b),(c)) <0) goto block_err |
278 | 0 | #define BLOCK_APPEND_UINT(b,i) if (block_append_uint((b),(i)) <0) goto block_err |
279 | | |
280 | 0 | static inline unsigned char *append_uint32(unsigned char *cp, uint32_t i) { |
281 | 0 | uint32_t j; |
282 | |
|
283 | 0 | if (i == 0) { |
284 | 0 | *cp++ = '0'; |
285 | 0 | return cp; |
286 | 0 | } |
287 | | |
288 | 0 | if (i < 100) goto b1; |
289 | 0 | if (i < 10000) goto b3; |
290 | 0 | if (i < 1000000) goto b5; |
291 | 0 | if (i < 100000000) goto b7; |
292 | | |
293 | 0 | if ((j = i / 1000000000)) {*cp++ = j + '0'; i -= j*1000000000; goto x8;} |
294 | 0 | if ((j = i / 100000000)) {*cp++ = j + '0'; i -= j*100000000; goto x7;} |
295 | 0 | b7:if ((j = i / 10000000)) {*cp++ = j + '0'; i -= j*10000000; goto x6;} |
296 | 0 | if ((j = i / 1000000)) {*cp++ = j + '0', i -= j*1000000; goto x5;} |
297 | 0 | b5:if ((j = i / 100000)) {*cp++ = j + '0', i -= j*100000; goto x4;} |
298 | 0 | if ((j = i / 10000)) {*cp++ = j + '0', i -= j*10000; goto x3;} |
299 | 0 | b3:if ((j = i / 1000)) {*cp++ = j + '0', i -= j*1000; goto x2;} |
300 | 0 | if ((j = i / 100)) {*cp++ = j + '0', i -= j*100; goto x1;} |
301 | 0 | b1:if ((j = i / 10)) {*cp++ = j + '0', i -= j*10; goto x0;} |
302 | 0 | if (i) *cp++ = i + '0'; |
303 | 0 | return cp; |
304 | | |
305 | 0 | x8: *cp++ = i / 100000000 + '0', i %= 100000000; |
306 | 0 | x7: *cp++ = i / 10000000 + '0', i %= 10000000; |
307 | 0 | x6: *cp++ = i / 1000000 + '0', i %= 1000000; |
308 | 0 | x5: *cp++ = i / 100000 + '0', i %= 100000; |
309 | 0 | x4: *cp++ = i / 10000 + '0', i %= 10000; |
310 | 0 | x3: *cp++ = i / 1000 + '0', i %= 1000; |
311 | 0 | x2: *cp++ = i / 100 + '0', i %= 100; |
312 | 0 | x1: *cp++ = i / 10 + '0', i %= 10; |
313 | 0 | x0: *cp++ = i + '0'; |
314 | |
|
315 | 0 | return cp; |
316 | 0 | } Unexecuted instantiation: hts.c:append_uint32 Unexecuted instantiation: sam.c:append_uint32 Unexecuted instantiation: cram_decode.c:append_uint32 Unexecuted instantiation: cram_encode.c:append_uint32 Unexecuted instantiation: cram_index.c:append_uint32 Unexecuted instantiation: cram_io.c:append_uint32 Unexecuted instantiation: cram_stats.c:append_uint32 Unexecuted instantiation: cram_codecs.c:append_uint32 |
317 | | |
318 | 0 | static inline unsigned char *append_sub32(unsigned char *cp, uint32_t i) { |
319 | 0 | *cp++ = i / 100000000 + '0', i %= 100000000; |
320 | 0 | *cp++ = i / 10000000 + '0', i %= 10000000; |
321 | 0 | *cp++ = i / 1000000 + '0', i %= 1000000; |
322 | 0 | *cp++ = i / 100000 + '0', i %= 100000; |
323 | 0 | *cp++ = i / 10000 + '0', i %= 10000; |
324 | 0 | *cp++ = i / 1000 + '0', i %= 1000; |
325 | 0 | *cp++ = i / 100 + '0', i %= 100; |
326 | 0 | *cp++ = i / 10 + '0', i %= 10; |
327 | 0 | *cp++ = i + '0'; |
328 | |
|
329 | 0 | return cp; |
330 | 0 | } Unexecuted instantiation: hts.c:append_sub32 Unexecuted instantiation: sam.c:append_sub32 Unexecuted instantiation: cram_decode.c:append_sub32 Unexecuted instantiation: cram_encode.c:append_sub32 Unexecuted instantiation: cram_index.c:append_sub32 Unexecuted instantiation: cram_io.c:append_sub32 Unexecuted instantiation: cram_stats.c:append_sub32 Unexecuted instantiation: cram_codecs.c:append_sub32 |
331 | | |
332 | 0 | static inline unsigned char *append_uint64(unsigned char *cp, uint64_t i) { |
333 | 0 | uint64_t j; |
334 | |
|
335 | 0 | if (i <= 0xffffffff) |
336 | 0 | return append_uint32(cp, i); |
337 | | |
338 | 0 | if ((j = i/1000000000) > 1000000000) { |
339 | 0 | cp = append_uint32(cp, j/1000000000); |
340 | 0 | j %= 1000000000; |
341 | 0 | cp = append_sub32(cp, j); |
342 | 0 | } else { |
343 | 0 | cp = append_uint32(cp, i / 1000000000); |
344 | 0 | } |
345 | 0 | cp = append_sub32(cp, i % 1000000000); |
346 | |
|
347 | 0 | return cp; |
348 | 0 | } Unexecuted instantiation: hts.c:append_uint64 Unexecuted instantiation: sam.c:append_uint64 Unexecuted instantiation: cram_decode.c:append_uint64 Unexecuted instantiation: cram_encode.c:append_uint64 Unexecuted instantiation: cram_index.c:append_uint64 Unexecuted instantiation: cram_io.c:append_uint64 Unexecuted instantiation: cram_stats.c:append_uint64 Unexecuted instantiation: cram_codecs.c:append_uint64 |
349 | | |
350 | | #define BLOCK_UPLEN(b) \ |
351 | 399k | (b)->comp_size = (b)->uncomp_size = BLOCK_SIZE((b)) |
352 | | |
353 | | /**@}*/ |
354 | | /**@{ ---------------------------------------------------------------------- |
355 | | * Reference sequence handling |
356 | | */ |
357 | | |
358 | | /*! Loads a reference set from fn and stores in the cram_fd. |
359 | | * |
360 | | * @return |
361 | | * Returns 0 on success; |
362 | | * -1 on failure |
363 | | */ |
364 | | int cram_load_reference(cram_fd *fd, char *fn); |
365 | | |
366 | | /*! Generates a lookup table in refs based on the SQ headers in sam_hdr_t. |
367 | | * |
368 | | * Indexes references by the order they appear in a BAM file. This may not |
369 | | * necessarily be the same order they appear in the fasta reference file. |
370 | | * |
371 | | * @return |
372 | | * Returns 0 on success; |
373 | | * -1 on failure |
374 | | */ |
375 | | int refs2id(refs_t *r, sam_hdr_t *hdr); |
376 | | |
377 | | void refs_free(refs_t *r); |
378 | | |
379 | | /*! Returns a portion of a reference sequence from start to end inclusive. |
380 | | * |
381 | | * The returned pointer is owned by the cram_file fd and should not be freed |
382 | | * by the caller. It is valid only until the next cram_get_ref is called |
383 | | * with the same fd parameter (so is thread-safe if given multiple files). |
384 | | * |
385 | | * To return the entire reference sequence, specify start as 1 and end |
386 | | * as 0. |
387 | | * |
388 | | * @return |
389 | | * Returns reference on success; |
390 | | * NULL on failure |
391 | | */ |
392 | | char *cram_get_ref(cram_fd *fd, int id, hts_pos_t start, hts_pos_t end); |
393 | | void cram_ref_incr(refs_t *r, int id); |
394 | | void cram_ref_decr(refs_t *r, int id); |
395 | | /**@}*/ |
396 | | /**@{ ---------------------------------------------------------------------- |
397 | | * Containers |
398 | | */ |
399 | | |
400 | | /*! Creates a new container, specifying the maximum number of slices |
401 | | * and records permitted. |
402 | | * |
403 | | * @return |
404 | | * Returns cram_container ptr on success; |
405 | | * NULL on failure |
406 | | */ |
407 | | cram_container *cram_new_container(int nrec, int nslice); |
408 | | void cram_free_container(cram_container *c); |
409 | | |
410 | | /*! Reads a container header. |
411 | | * |
412 | | * @return |
413 | | * Returns cram_container on success; |
414 | | * NULL on failure or no container left (fd->err == 0). |
415 | | */ |
416 | | cram_container *cram_read_container(cram_fd *fd); |
417 | | |
418 | | /*! Writes a container structure. |
419 | | * |
420 | | * @return |
421 | | * Returns 0 on success; |
422 | | * -1 on failure |
423 | | */ |
424 | | int cram_write_container(cram_fd *fd, cram_container *h); |
425 | | |
426 | | /*! Flushes a container to disk. |
427 | | * |
428 | | * Flushes a completely or partially full container to disk, writing |
429 | | * container structure, header and blocks. This also calls the encoder |
430 | | * functions. |
431 | | * |
432 | | * @return |
433 | | * Returns 0 on success; |
434 | | * -1 on failure |
435 | | */ |
436 | | int cram_flush_container(cram_fd *fd, cram_container *c); |
437 | | int cram_flush_container_mt(cram_fd *fd, cram_container *c); |
438 | | |
439 | | |
440 | | /**@}*/ |
441 | | /**@{ ---------------------------------------------------------------------- |
442 | | * Compression headers; the first part of the container |
443 | | */ |
444 | | |
445 | | /*! Creates a new blank container compression header |
446 | | * |
447 | | * @return |
448 | | * Returns header ptr on success; |
449 | | * NULL on failure |
450 | | */ |
451 | | cram_block_compression_hdr *cram_new_compression_header(void); |
452 | | |
453 | | /*! Frees a cram_block_compression_hdr */ |
454 | | void cram_free_compression_header(cram_block_compression_hdr *hdr); |
455 | | |
456 | | |
457 | | /**@}*/ |
458 | | /**@{ ---------------------------------------------------------------------- |
459 | | * Slices and slice headers |
460 | | */ |
461 | | |
462 | | /*! Frees a slice header */ |
463 | | void cram_free_slice_header(cram_block_slice_hdr *hdr); |
464 | | |
465 | | /*! Frees a slice */ |
466 | | void cram_free_slice(cram_slice *s); |
467 | | |
468 | | /*! Creates a new empty slice in memory, for subsequent writing to |
469 | | * disk. |
470 | | * |
471 | | * @return |
472 | | * Returns cram_slice ptr on success; |
473 | | * NULL on failure |
474 | | */ |
475 | | cram_slice *cram_new_slice(enum cram_content_type type, int nrecs); |
476 | | |
477 | | /*! Loads an entire slice. |
478 | | * |
479 | | * FIXME: In 1.0 the native unit of slices within CRAM is broken |
480 | | * as slices contain references to objects in other slices. |
481 | | * To work around this while keeping the slice oriented outer loop |
482 | | * we read all slices and stitch them together into a fake large |
483 | | * slice instead. |
484 | | * |
485 | | * @return |
486 | | * Returns cram_slice ptr on success; |
487 | | * NULL on failure |
488 | | */ |
489 | | cram_slice *cram_read_slice(cram_fd *fd); |
490 | | |
491 | | |
492 | | |
493 | | /**@}*/ |
494 | | /**@{ ---------------------------------------------------------------------- |
495 | | * CRAM file definition (header) |
496 | | */ |
497 | | |
498 | | /*! Reads a CRAM file definition structure. |
499 | | * |
500 | | * @return |
501 | | * Returns file_def ptr on success; |
502 | | * NULL on failure |
503 | | */ |
504 | | cram_file_def *cram_read_file_def(cram_fd *fd); |
505 | | |
506 | | /*! Writes a cram_file_def structure to cram_fd. |
507 | | * |
508 | | * @return |
509 | | * Returns 0 on success; |
510 | | * -1 on failure |
511 | | */ |
512 | | int cram_write_file_def(cram_fd *fd, cram_file_def *def); |
513 | | |
514 | | /*! Frees a cram_file_def structure. */ |
515 | | void cram_free_file_def(cram_file_def *def); |
516 | | |
517 | | |
518 | | /**@}*/ |
519 | | /**@{ ---------------------------------------------------------------------- |
520 | | * SAM header I/O |
521 | | */ |
522 | | |
523 | | /*! Reads the SAM header from the first CRAM data block. |
524 | | * |
525 | | * Also performs minimal parsing to extract read-group |
526 | | * and sample information. |
527 | | * |
528 | | * @return |
529 | | * Returns SAM hdr ptr on success; |
530 | | * NULL on failure |
531 | | */ |
532 | | sam_hdr_t *cram_read_SAM_hdr(cram_fd *fd); |
533 | | |
534 | | /*! Writes a CRAM SAM header. |
535 | | * |
536 | | * @return |
537 | | * Returns 0 on success; |
538 | | * -1 on failure |
539 | | */ |
540 | | int cram_write_SAM_hdr(cram_fd *fd, sam_hdr_t *hdr); |
541 | | |
542 | | |
543 | | /**@}*/ |
544 | | /**@{ ---------------------------------------------------------------------- |
545 | | * The top-level cram opening, closing and option handling |
546 | | */ |
547 | | |
548 | | /*! Opens a CRAM file for read (mode "rb") or write ("wb"). |
549 | | * |
550 | | * The filename may be "-" to indicate stdin or stdout. |
551 | | * |
552 | | * @return |
553 | | * Returns file handle on success; |
554 | | * NULL on failure. |
555 | | */ |
556 | | cram_fd *cram_open(const char *filename, const char *mode); |
557 | | |
558 | | /*! Opens an existing stream for reading or writing. |
559 | | * |
560 | | * @return |
561 | | * Returns file handle on success; |
562 | | * NULL on failure. |
563 | | */ |
564 | | cram_fd *cram_dopen(struct hFILE *fp, const char *filename, const char *mode); |
565 | | |
566 | | /*! Closes a CRAM file. |
567 | | * |
568 | | * @return |
569 | | * Returns 0 on success; |
570 | | * -1 on failure |
571 | | */ |
572 | | int cram_close(cram_fd *fd); |
573 | | |
574 | | /* |
575 | | * Seek within a CRAM file. |
576 | | * |
577 | | * Returns 0 on success |
578 | | * -1 on failure |
579 | | */ |
580 | | int cram_seek(cram_fd *fd, off_t offset, int whence); |
581 | | |
582 | | /* |
583 | | * Flushes a CRAM file. |
584 | | * Useful for when writing to stdout without wishing to close the stream. |
585 | | * |
586 | | * Returns 0 on success |
587 | | * -1 on failure |
588 | | */ |
589 | | int cram_flush(cram_fd *fd); |
590 | | |
591 | | /*! Checks for end of file on a cram_fd stream. |
592 | | * |
593 | | * @return |
594 | | * Returns 0 if not at end of file |
595 | | * 1 if we hit an expected EOF (end of range or EOF block) |
596 | | * 2 for other EOF (end of stream without EOF block) |
597 | | */ |
598 | | int cram_eof(cram_fd *fd); |
599 | | |
600 | | /*! Sets options on the cram_fd. |
601 | | * |
602 | | * See CRAM_OPT_* definitions in cram_structs.h. |
603 | | * Use this immediately after opening. |
604 | | * |
605 | | * @return |
606 | | * Returns 0 on success; |
607 | | * -1 on failure |
608 | | */ |
609 | | int cram_set_option(cram_fd *fd, enum hts_fmt_option opt, ...); |
610 | | |
611 | | /*! Sets options on the cram_fd. |
612 | | * |
613 | | * See CRAM_OPT_* definitions in cram_structs.h. |
614 | | * Use this immediately after opening. |
615 | | * |
616 | | * @return |
617 | | * Returns 0 on success; |
618 | | * -1 on failure |
619 | | */ |
620 | | int cram_set_voption(cram_fd *fd, enum hts_fmt_option opt, va_list args); |
621 | | |
622 | | /*! |
623 | | * Attaches a header to a cram_fd. |
624 | | * |
625 | | * This should be used when creating a new cram_fd for writing where |
626 | | * we have an sam_hdr_t already constructed (eg from a file we've read |
627 | | * in). |
628 | | * |
629 | | * @return |
630 | | * Returns 0 on success; |
631 | | * -1 on failure |
632 | | */ |
633 | | int cram_set_header2(cram_fd *fd, const sam_hdr_t *hdr); |
634 | | |
635 | | /*! |
636 | | * Returns the hFILE connected to a cram_fd. |
637 | | */ |
638 | 0 | static inline struct hFILE *cram_hfile(cram_fd *fd) { |
639 | 0 | return fd->fp; |
640 | 0 | } Unexecuted instantiation: hts.c:cram_hfile Unexecuted instantiation: sam.c:cram_hfile Unexecuted instantiation: cram_decode.c:cram_hfile Unexecuted instantiation: cram_encode.c:cram_hfile Unexecuted instantiation: cram_index.c:cram_hfile Unexecuted instantiation: cram_io.c:cram_hfile Unexecuted instantiation: cram_stats.c:cram_hfile Unexecuted instantiation: cram_codecs.c:cram_hfile |
641 | | |
642 | | #ifdef __cplusplus |
643 | | } |
644 | | #endif |
645 | | |
646 | | #endif /* CRAM_IO_H */ |