Coverage Report

Created: 2026-09-28 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/htslib/cram/cram_encode.c
Line
Count
Source
1
/*
2
Copyright (c) 2012-2020, 2022-2026 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
#define HTS_BUILDING_LIBRARY // Enables HTSLIB_EXPORT, see htslib/hts_defs.h
32
#include <config.h>
33
34
#include <stdio.h>
35
#include <errno.h>
36
#include <assert.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <strings.h>
40
#include <zlib.h>
41
#include <sys/types.h>
42
#include <sys/stat.h>
43
#include <math.h>
44
#include <inttypes.h>
45
#include <ctype.h>
46
47
#include "cram.h"
48
#include "os.h"
49
#include "../sam_internal.h" // for nibble2base
50
#include "../htslib/hts.h"
51
#include "../htslib/hts_alloc.h"
52
#include "../htslib/hts_endian.h"
53
#include "../textutils_internal.h"
54
55
0
KHASH_MAP_INIT_STR(m_s2u64, uint64_t)
56
0
57
0
#define Z_CRAM_STRAT Z_FILTERED
58
0
//#define Z_CRAM_STRAT Z_RLE
59
0
//#define Z_CRAM_STRAT Z_HUFFMAN_ONLY
60
0
//#define Z_CRAM_STRAT Z_DEFAULT_STRATEGY
61
0
62
0
static int process_one_read(cram_fd *fd, cram_container *c,
63
0
                            cram_slice *s, cram_record *cr,
64
0
                            bam_seq_t *b, int rnum, kstring_t *MD,
65
0
                            int embed_ref, int no_ref);
66
0
67
0
/*
68
0
 * Returns index of val into key.
69
0
 * Basically strchr(key, val)-key;
70
0
 */
71
691k
static int sub_idx(char *key, char val) {
72
691k
    int i;
73
74
1.72M
    for (i = 0; i < 4 && *key++ != val; i++);
75
691k
    return i;
76
691k
}
77
78
/*
79
 * Encodes a compression header block into a generic cram_block structure.
80
 *
81
 * Returns cram_block ptr on success
82
 *         NULL on failure
83
 */
84
cram_block *cram_encode_compression_header(cram_fd *fd, cram_container *c,
85
                                           cram_block_compression_hdr *h,
86
44.6k
                                           int embed_ref) {
87
44.6k
    cram_block *cb  = cram_new_block(COMPRESSION_HEADER, 0);
88
44.6k
    cram_block *map = cram_new_block(COMPRESSION_HEADER, 0);
89
44.6k
    int i, mc, r = 0;
90
91
44.6k
    int no_ref = c->no_ref;
92
93
44.6k
    if (!cb || !map)
94
0
        return NULL;
95
96
    /*
97
     * This is a concatenation of several blocks of data:
98
     * header + landmarks, preservation map, read encoding map, and the tag
99
     * encoding map.
100
     * All 4 are variable sized and we need to know how large these are
101
     * before creating the compression header itself as this starts with
102
     * the total size (stored as a variable length string).
103
     */
104
105
    // Duplicated from container itself, and removed in 1.1
106
44.6k
    if (CRAM_MAJOR_VERS(fd->version) == 1) {
107
0
        r |= itf8_put_blk(cb, h->ref_seq_id);
108
0
        r |= itf8_put_blk(cb, h->ref_seq_start);
109
0
        r |= itf8_put_blk(cb, h->ref_seq_span);
110
0
        r |= itf8_put_blk(cb, h->num_records);
111
0
        r |= itf8_put_blk(cb, h->num_landmarks);
112
0
        for (i = 0; i < h->num_landmarks; i++) {
113
0
            r |= itf8_put_blk(cb, h->landmark[i]);
114
0
        }
115
0
    }
116
117
44.6k
    if (h->preservation_map) {
118
0
        kh_destroy(map, h->preservation_map);
119
0
        h->preservation_map = NULL;
120
0
    }
121
122
    /* Create in-memory preservation map */
123
    /* FIXME: should create this when we create the container */
124
44.6k
    if (c->num_records > 0) {
125
34.5k
        khint_t k;
126
34.5k
        int r;
127
128
34.5k
        if (!(h->preservation_map = kh_init(map)))
129
0
            return NULL;
130
131
34.5k
        k = kh_put(map, h->preservation_map, "RN", &r);
132
34.5k
        if (-1 == r) return NULL;
133
34.5k
        kh_val(h->preservation_map, k).i = !fd->lossy_read_names;
134
135
34.5k
        if (CRAM_MAJOR_VERS(fd->version) == 1) {
136
0
            k = kh_put(map, h->preservation_map, "PI", &r);
137
0
            if (-1 == r) return NULL;
138
0
            kh_val(h->preservation_map, k).i = 0;
139
140
0
            k = kh_put(map, h->preservation_map, "UI", &r);
141
0
            if (-1 == r) return NULL;
142
0
            kh_val(h->preservation_map, k).i = 1;
143
144
0
            k = kh_put(map, h->preservation_map, "MI", &r);
145
0
            if (-1 == r) return NULL;
146
0
            kh_val(h->preservation_map, k).i = 1;
147
148
34.5k
        } else {
149
            // Technically SM was in 1.0, but wasn't in Java impl.
150
34.5k
            k = kh_put(map, h->preservation_map, "SM", &r);
151
34.5k
            if (-1 == r) return NULL;
152
34.5k
            kh_val(h->preservation_map, k).i = 0;
153
154
34.5k
            k = kh_put(map, h->preservation_map, "TD", &r);
155
34.5k
            if (-1 == r) return NULL;
156
34.5k
            kh_val(h->preservation_map, k).i = 0;
157
158
34.5k
            k = kh_put(map, h->preservation_map, "AP", &r);
159
34.5k
            if (-1 == r) return NULL;
160
34.5k
            kh_val(h->preservation_map, k).i = h->AP_delta;
161
162
34.5k
            if (no_ref || embed_ref>0) {
163
                // Reference Required == No
164
30.4k
                k = kh_put(map, h->preservation_map, "RR", &r);
165
30.4k
                if (-1 == r) return NULL;
166
30.4k
                kh_val(h->preservation_map, k).i = 0;
167
30.4k
            }
168
34.5k
        }
169
34.5k
    }
170
171
    /* Encode preservation map; could collapse this and above into one */
172
44.6k
    mc = 0;
173
44.6k
    BLOCK_SIZE(map) = 0;
174
44.6k
    if (h->preservation_map) {
175
34.5k
        khint_t k;
176
177
34.5k
        for (k = kh_begin(h->preservation_map);
178
311k
             k != kh_end(h->preservation_map);
179
276k
             k++) {
180
276k
            const char *key;
181
276k
            khash_t(map) *pmap = h->preservation_map;
182
183
184
276k
            if (!kh_exist(pmap, k))
185
107k
                continue;
186
187
168k
            key = kh_key(pmap, k);
188
168k
            BLOCK_APPEND(map, key, 2);
189
190
168k
            switch(CRAM_KEY(key[0], key[1])) {
191
0
            case CRAM_KEY('M','I'):
192
0
            case CRAM_KEY('U','I'):
193
0
            case CRAM_KEY('P','I'):
194
34.5k
            case CRAM_KEY('A','P'):
195
69.1k
            case CRAM_KEY('R','N'):
196
99.6k
            case CRAM_KEY('R','R'):
197
99.6k
            case CRAM_KEY('Q','O'):
198
99.6k
                BLOCK_APPEND_CHAR(map, kh_val(pmap, k).i);
199
99.6k
                break;
200
201
99.6k
            case CRAM_KEY('S','M'): {
202
34.5k
                char smat[5], *mp = smat;
203
                // Output format is for order ACGTN (minus ref base)
204
                // to store the code value 0-3 for each symbol.
205
                //
206
                // Note this is different to storing the symbols in order
207
                // that the codes occur from 0-3, which is what we used to
208
                // do.  (It didn't matter as we always had a fixed table in
209
                // the order.)
210
34.5k
                *mp++ =
211
34.5k
                    (sub_idx(h->substitution_matrix[0], 'C') << 6) |
212
34.5k
                    (sub_idx(h->substitution_matrix[0], 'G') << 4) |
213
34.5k
                    (sub_idx(h->substitution_matrix[0], 'T') << 2) |
214
34.5k
                    (sub_idx(h->substitution_matrix[0], 'N') << 0);
215
34.5k
                *mp++ =
216
34.5k
                    (sub_idx(h->substitution_matrix[1], 'A') << 6) |
217
34.5k
                    (sub_idx(h->substitution_matrix[1], 'G') << 4) |
218
34.5k
                    (sub_idx(h->substitution_matrix[1], 'T') << 2) |
219
34.5k
                    (sub_idx(h->substitution_matrix[1], 'N') << 0);
220
34.5k
                *mp++ =
221
34.5k
                    (sub_idx(h->substitution_matrix[2], 'A') << 6) |
222
34.5k
                    (sub_idx(h->substitution_matrix[2], 'C') << 4) |
223
34.5k
                    (sub_idx(h->substitution_matrix[2], 'T') << 2) |
224
34.5k
                    (sub_idx(h->substitution_matrix[2], 'N') << 0);
225
34.5k
                *mp++ =
226
34.5k
                    (sub_idx(h->substitution_matrix[3], 'A') << 6) |
227
34.5k
                    (sub_idx(h->substitution_matrix[3], 'C') << 4) |
228
34.5k
                    (sub_idx(h->substitution_matrix[3], 'G') << 2) |
229
34.5k
                    (sub_idx(h->substitution_matrix[3], 'N') << 0);
230
34.5k
                *mp++ =
231
34.5k
                    (sub_idx(h->substitution_matrix[4], 'A') << 6) |
232
34.5k
                    (sub_idx(h->substitution_matrix[4], 'C') << 4) |
233
34.5k
                    (sub_idx(h->substitution_matrix[4], 'G') << 2) |
234
34.5k
                    (sub_idx(h->substitution_matrix[4], 'T') << 0);
235
34.5k
                BLOCK_APPEND(map, smat, 5);
236
34.5k
                break;
237
34.5k
            }
238
239
34.5k
            case CRAM_KEY('T','D'): {
240
34.5k
                r |= (fd->vv.varint_put32_blk(map, BLOCK_SIZE(h->TD_blk)) <= 0);
241
34.5k
                BLOCK_APPEND(map,
242
34.5k
                             BLOCK_DATA(h->TD_blk),
243
34.5k
                             BLOCK_SIZE(h->TD_blk));
244
34.5k
                break;
245
34.5k
            }
246
247
34.5k
            default:
248
0
                hts_log_warning("Unknown preservation key '%.2s'", key);
249
0
                break;
250
168k
            }
251
252
168k
            mc++;
253
168k
        }
254
34.5k
    }
255
44.6k
    r |= (fd->vv.varint_put32_blk(cb, BLOCK_SIZE(map) + fd->vv.varint_size(mc)) <= 0);
256
44.6k
    r |= (fd->vv.varint_put32_blk(cb, mc) <= 0);
257
44.6k
    BLOCK_APPEND(cb, BLOCK_DATA(map), BLOCK_SIZE(map));
258
259
    /* rec encoding map */
260
44.6k
    mc = 0;
261
44.6k
    BLOCK_SIZE(map) = 0;
262
44.6k
    if (h->codecs[DS_BF]) {
263
34.5k
        if (-1 == h->codecs[DS_BF]->store(h->codecs[DS_BF], map, "BF",
264
34.5k
                                          fd->version))
265
0
            return NULL;
266
34.5k
        mc++;
267
34.5k
    }
268
44.6k
    if (h->codecs[DS_CF]) {
269
34.5k
        if (-1 == h->codecs[DS_CF]->store(h->codecs[DS_CF], map, "CF",
270
34.5k
                                          fd->version))
271
0
            return NULL;
272
34.5k
        mc++;
273
34.5k
    }
274
44.6k
    if (h->codecs[DS_RL]) {
275
34.5k
        if (-1 == h->codecs[DS_RL]->store(h->codecs[DS_RL], map, "RL",
276
34.5k
                                          fd->version))
277
0
            return NULL;
278
34.5k
        mc++;
279
34.5k
    }
280
44.6k
    if (h->codecs[DS_AP]) {
281
34.5k
        if (-1 == h->codecs[DS_AP]->store(h->codecs[DS_AP], map, "AP",
282
34.5k
                                          fd->version))
283
0
            return NULL;
284
34.5k
        mc++;
285
34.5k
    }
286
44.6k
    if (h->codecs[DS_RG]) {
287
34.5k
        if (-1 == h->codecs[DS_RG]->store(h->codecs[DS_RG], map, "RG",
288
34.5k
                                          fd->version))
289
0
            return NULL;
290
34.5k
        mc++;
291
34.5k
    }
292
44.6k
    if (h->codecs[DS_MF]) {
293
34.5k
        if (-1 == h->codecs[DS_MF]->store(h->codecs[DS_MF], map, "MF",
294
34.5k
                                          fd->version))
295
0
            return NULL;
296
34.5k
        mc++;
297
34.5k
    }
298
44.6k
    if (h->codecs[DS_NS]) {
299
34.5k
        if (-1 == h->codecs[DS_NS]->store(h->codecs[DS_NS], map, "NS",
300
34.5k
                                          fd->version))
301
0
            return NULL;
302
34.5k
        mc++;
303
34.5k
    }
304
44.6k
    if (h->codecs[DS_NP]) {
305
34.5k
        if (-1 == h->codecs[DS_NP]->store(h->codecs[DS_NP], map, "NP",
306
34.5k
                                          fd->version))
307
0
            return NULL;
308
34.5k
        mc++;
309
34.5k
    }
310
44.6k
    if (h->codecs[DS_TS]) {
311
34.5k
        if (-1 == h->codecs[DS_TS]->store(h->codecs[DS_TS], map, "TS",
312
34.5k
                                          fd->version))
313
0
            return NULL;
314
34.5k
        mc++;
315
34.5k
    }
316
44.6k
    if (h->codecs[DS_NF]) {
317
3
        if (-1 == h->codecs[DS_NF]->store(h->codecs[DS_NF], map, "NF",
318
3
                                          fd->version))
319
0
            return NULL;
320
3
        mc++;
321
3
    }
322
44.6k
    if (h->codecs[DS_TC]) {
323
0
        if (-1 == h->codecs[DS_TC]->store(h->codecs[DS_TC], map, "TC",
324
0
                                          fd->version))
325
0
            return NULL;
326
0
        mc++;
327
0
    }
328
44.6k
    if (h->codecs[DS_TN]) {
329
0
        if (-1 == h->codecs[DS_TN]->store(h->codecs[DS_TN], map, "TN",
330
0
                                          fd->version))
331
0
            return NULL;
332
0
        mc++;
333
0
    }
334
44.6k
    if (h->codecs[DS_TL]) {
335
34.5k
        if (-1 == h->codecs[DS_TL]->store(h->codecs[DS_TL], map, "TL",
336
34.5k
                                          fd->version))
337
0
            return NULL;
338
34.5k
        mc++;
339
34.5k
    }
340
44.6k
    if (h->codecs[DS_FN]) {
341
14.9k
        if (-1 == h->codecs[DS_FN]->store(h->codecs[DS_FN], map, "FN",
342
14.9k
                                          fd->version))
343
0
            return NULL;
344
14.9k
        mc++;
345
14.9k
    }
346
44.6k
    if (h->codecs[DS_FC]) {
347
14.7k
        if (-1 == h->codecs[DS_FC]->store(h->codecs[DS_FC], map, "FC",
348
14.7k
                                          fd->version))
349
0
            return NULL;
350
14.7k
        mc++;
351
14.7k
    }
352
44.6k
    if (h->codecs[DS_FP]) {
353
14.7k
        if (-1 == h->codecs[DS_FP]->store(h->codecs[DS_FP], map, "FP",
354
14.7k
                                          fd->version))
355
0
            return NULL;
356
14.7k
        mc++;
357
14.7k
    }
358
44.6k
    if (h->codecs[DS_BS]) {
359
923
        if (-1 == h->codecs[DS_BS]->store(h->codecs[DS_BS], map, "BS",
360
923
                                          fd->version))
361
0
            return NULL;
362
923
        mc++;
363
923
    }
364
44.6k
    if (h->codecs[DS_IN]) {
365
34.5k
        if (-1 == h->codecs[DS_IN]->store(h->codecs[DS_IN], map, "IN",
366
34.5k
                                          fd->version))
367
0
            return NULL;
368
34.5k
        mc++;
369
34.5k
    }
370
44.6k
    if (h->codecs[DS_DL]) {
371
8.26k
        if (-1 == h->codecs[DS_DL]->store(h->codecs[DS_DL], map, "DL",
372
8.26k
                                          fd->version))
373
0
            return NULL;
374
8.26k
        mc++;
375
8.26k
    }
376
44.6k
    if (h->codecs[DS_BA]) {
377
9.10k
        if (-1 == h->codecs[DS_BA]->store(h->codecs[DS_BA], map, "BA",
378
9.10k
                                          fd->version))
379
0
            return NULL;
380
9.10k
        mc++;
381
9.10k
    }
382
44.6k
    if (h->codecs[DS_BB]) {
383
34.5k
        if (-1 == h->codecs[DS_BB]->store(h->codecs[DS_BB], map, "BB",
384
34.5k
                                          fd->version))
385
0
            return NULL;
386
34.5k
        mc++;
387
34.5k
    }
388
44.6k
    if (h->codecs[DS_MQ]) {
389
34.5k
        if (-1 == h->codecs[DS_MQ]->store(h->codecs[DS_MQ], map, "MQ",
390
34.5k
                                          fd->version))
391
0
            return NULL;
392
34.5k
        mc++;
393
34.5k
    }
394
44.6k
    if (h->codecs[DS_RN]) {
395
34.5k
        if (-1 == h->codecs[DS_RN]->store(h->codecs[DS_RN], map, "RN",
396
34.5k
                                          fd->version))
397
0
            return NULL;
398
34.5k
        mc++;
399
34.5k
    }
400
44.6k
    if (h->codecs[DS_QS]) {
401
34.5k
        if (-1 == h->codecs[DS_QS]->store(h->codecs[DS_QS], map, "QS",
402
34.5k
                                          fd->version))
403
0
            return NULL;
404
34.5k
        mc++;
405
34.5k
    }
406
44.6k
    if (h->codecs[DS_QQ]) {
407
0
        if (-1 == h->codecs[DS_QQ]->store(h->codecs[DS_QQ], map, "QQ",
408
0
                                          fd->version))
409
0
            return NULL;
410
0
        mc++;
411
0
    }
412
44.6k
    if (h->codecs[DS_RI]) {
413
34.5k
        if (-1 == h->codecs[DS_RI]->store(h->codecs[DS_RI], map, "RI",
414
34.5k
                                          fd->version))
415
0
            return NULL;
416
34.5k
        mc++;
417
34.5k
    }
418
44.6k
    if (CRAM_MAJOR_VERS(fd->version) != 1) {
419
44.6k
        if (h->codecs[DS_SC]) {
420
34.5k
            if (-1 == h->codecs[DS_SC]->store(h->codecs[DS_SC], map, "SC",
421
34.5k
                                              fd->version))
422
0
                return NULL;
423
34.5k
            mc++;
424
34.5k
        }
425
44.6k
        if (h->codecs[DS_RS]) {
426
84
            if (-1 == h->codecs[DS_RS]->store(h->codecs[DS_RS], map, "RS",
427
84
                                              fd->version))
428
0
                return NULL;
429
84
            mc++;
430
84
        }
431
44.6k
        if (h->codecs[DS_PD]) {
432
139
            if (-1 == h->codecs[DS_PD]->store(h->codecs[DS_PD], map, "PD",
433
139
                                              fd->version))
434
0
                return NULL;
435
139
            mc++;
436
139
        }
437
44.6k
        if (h->codecs[DS_HC]) {
438
4.54k
            if (-1 == h->codecs[DS_HC]->store(h->codecs[DS_HC], map, "HC",
439
4.54k
                                              fd->version))
440
0
                return NULL;
441
4.54k
            mc++;
442
4.54k
        }
443
44.6k
    }
444
44.6k
    if (h->codecs[DS_TM]) {
445
0
        if (-1 == h->codecs[DS_TM]->store(h->codecs[DS_TM], map, "TM",
446
0
                                          fd->version))
447
0
            return NULL;
448
0
        mc++;
449
0
    }
450
44.6k
    if (h->codecs[DS_TV]) {
451
0
        if (-1 == h->codecs[DS_TV]->store(h->codecs[DS_TV], map, "TV",
452
0
                                          fd->version))
453
0
            return NULL;
454
0
        mc++;
455
0
    }
456
44.6k
    r |= (fd->vv.varint_put32_blk(cb, BLOCK_SIZE(map) + fd->vv.varint_size(mc)) <= 0);
457
44.6k
    r |= (fd->vv.varint_put32_blk(cb, mc) <= 0);
458
44.6k
    BLOCK_APPEND(cb, BLOCK_DATA(map), BLOCK_SIZE(map));
459
460
    /* tag encoding map */
461
44.6k
    mc = 0;
462
44.6k
    BLOCK_SIZE(map) = 0;
463
44.6k
    if (c->tags_used) {
464
34.5k
        khint_t k;
465
466
168k
        for (k = kh_begin(c->tags_used); k != kh_end(c->tags_used); k++) {
467
134k
            int key;
468
134k
            if (!kh_exist(c->tags_used, k))
469
74.8k
                continue;
470
471
59.3k
            key = kh_key(c->tags_used, k);
472
59.3k
            cram_codec *cd = kh_val(c->tags_used, k)->codec;
473
474
59.3k
            r |= (fd->vv.varint_put32_blk(map, key) <= 0);
475
59.3k
            if (-1 == cd->store(cd, map, NULL, fd->version))
476
0
                return NULL;
477
478
59.3k
            mc++;
479
59.3k
        }
480
34.5k
    }
481
482
44.6k
    r |= (fd->vv.varint_put32_blk(cb, BLOCK_SIZE(map) + fd->vv.varint_size(mc)) <= 0);
483
44.6k
    r |= (fd->vv.varint_put32_blk(cb, mc) <= 0);
484
44.6k
    BLOCK_APPEND(cb, BLOCK_DATA(map), BLOCK_SIZE(map));
485
486
44.6k
    hts_log_info("Wrote compression block header in %d bytes", (int)BLOCK_SIZE(cb));
487
488
44.6k
    BLOCK_UPLEN(cb);
489
490
44.6k
    cram_free_block(map);
491
492
44.6k
    if (r >= 0)
493
44.6k
        return cb;
494
495
0
 block_err:
496
0
    return NULL;
497
44.6k
}
498
499
500
/*
501
 * Encodes a slice compression header.
502
 *
503
 * Returns cram_block on success
504
 *         NULL on failure
505
 */
506
34.7k
cram_block *cram_encode_slice_header(cram_fd *fd, cram_slice *s) {
507
34.7k
    char *buf;
508
34.7k
    char *cp;
509
34.7k
    cram_block *b = cram_new_block(MAPPED_SLICE, 0);
510
34.7k
    int j;
511
512
34.7k
    if (!b)
513
0
        return NULL;
514
515
34.7k
    cp = buf = hts_malloc_pse(8, s->hdr->num_blocks, 5, 22+16);
516
34.7k
    if (NULL == buf) {
517
0
        cram_free_block(b);
518
0
        return NULL;
519
0
    }
520
521
34.7k
    cp += fd->vv.varint_put32s(cp, NULL, s->hdr->ref_seq_id);
522
34.7k
    if (s->hdr->ref_seq_start < 0 || s->hdr->ref_seq_start > INT_MAX) {
523
187
        hts_log_error("Reference position too large for CRAM 3");
524
187
        cram_free_block(b);
525
187
        free(buf);
526
187
        return NULL;
527
187
    }
528
34.5k
    cp += fd->vv.varint_put32(cp, NULL, s->hdr->ref_seq_start);
529
34.5k
    cp += fd->vv.varint_put32(cp, NULL, s->hdr->ref_seq_span);
530
34.5k
    cp += fd->vv.varint_put32(cp, NULL, s->hdr->num_records);
531
34.5k
    if (CRAM_MAJOR_VERS(fd->version) == 2)
532
0
        cp += fd->vv.varint_put32(cp, NULL, s->hdr->record_counter);
533
34.5k
    else if (CRAM_MAJOR_VERS(fd->version) >= 3)
534
34.5k
        cp += fd->vv.varint_put64(cp, NULL, s->hdr->record_counter);
535
34.5k
    cp += fd->vv.varint_put32(cp, NULL, s->hdr->num_blocks);
536
34.5k
    cp += fd->vv.varint_put32(cp, NULL, s->hdr->num_content_ids);
537
203k
    for (j = 0; j < s->hdr->num_content_ids; j++) {
538
168k
        cp += fd->vv.varint_put32(cp, NULL, s->hdr->block_content_ids[j]);
539
168k
    }
540
34.5k
    if (s->hdr->content_type == MAPPED_SLICE)
541
34.5k
        cp += fd->vv.varint_put32(cp, NULL, s->hdr->ref_base_id);
542
543
34.5k
    if (CRAM_MAJOR_VERS(fd->version) != 1) {
544
34.5k
        memcpy(cp, s->hdr->md5, 16); cp += 16;
545
34.5k
    }
546
547
34.5k
    assert(cp-buf <= 22+16+5*(8+s->hdr->num_blocks));
548
549
34.5k
    b->data = (unsigned char *)buf;
550
34.5k
    b->comp_size = b->uncomp_size = cp-buf;
551
552
34.5k
    return b;
553
34.5k
}
554
555
556
/*
557
 * Encodes a single read.
558
 *
559
 * Returns 0 on success
560
 *        -1 on failure
561
 */
562
static int cram_encode_slice_read(cram_fd *fd,
563
                                  cram_container *c,
564
                                  cram_block_compression_hdr *h,
565
                                  cram_slice *s,
566
                                  cram_record *cr,
567
9.41M
                                  int64_t *last_pos) {
568
9.41M
    int r = 0;
569
9.41M
    int32_t i32;
570
9.41M
    unsigned char uc;
571
572
    //fprintf(stderr, "Encode seq %d, %d/%d FN=%d, %s\n", rec, core->byte, core->bit, cr->nfeature, s->name_ds->str + cr->name);
573
574
    //printf("BF=0x%x\n", cr->flags);
575
    //      bf = cram_flag_swap[cr->flags];
576
9.41M
    i32 = fd->cram_flag_swap[cr->flags & 0xfff];
577
9.41M
    r |= h->codecs[DS_BF]->encode(s, h->codecs[DS_BF], (char *)&i32, 1);
578
579
9.41M
    i32 = cr->cram_flags & CRAM_FLAG_MASK;
580
9.41M
    r |= h->codecs[DS_CF]->encode(s, h->codecs[DS_CF], (char *)&i32, 1);
581
582
9.41M
    if (CRAM_MAJOR_VERS(fd->version) != 1 && s->hdr->ref_seq_id == -2)
583
19.7k
        r |= h->codecs[DS_RI]->encode(s, h->codecs[DS_RI], (char *)&cr->ref_id, 1);
584
585
9.41M
    r |= h->codecs[DS_RL]->encode(s, h->codecs[DS_RL], (char *)&cr->len, 1);
586
587
9.41M
    if (c->pos_sorted) {
588
9.39M
        i32 = cr->apos - *last_pos;
589
9.39M
        r |= h->codecs[DS_AP]->encode(s, h->codecs[DS_AP], (char *)&i32, 1);
590
9.39M
        *last_pos = cr->apos;
591
9.39M
    } else {
592
21.9k
        i32 = cr->apos;
593
21.9k
        r |= h->codecs[DS_AP]->encode(s, h->codecs[DS_AP], (char *)&i32, 1);
594
21.9k
    }
595
596
9.41M
    r |= h->codecs[DS_RG]->encode(s, h->codecs[DS_RG], (char *)&cr->rg, 1);
597
598
9.41M
    if (cr->cram_flags & CRAM_FLAG_DETACHED) {
599
9.41M
        i32 = cr->mate_flags;
600
9.41M
        r |= h->codecs[DS_MF]->encode(s, h->codecs[DS_MF], (char *)&i32, 1);
601
602
9.41M
        r |= h->codecs[DS_NS]->encode(s, h->codecs[DS_NS],
603
9.41M
                                      (char *)&cr->mate_ref_id, 1);
604
605
9.41M
        i32 = cr->mate_pos;
606
9.41M
        r |= h->codecs[DS_NP]->encode(s, h->codecs[DS_NP],
607
9.41M
                                      (char *)&i32, 1);
608
9.41M
        i32 = cr->tlen;
609
9.41M
        r |= h->codecs[DS_TS]->encode(s, h->codecs[DS_TS],
610
9.41M
                                      (char *)&i32, 1);
611
9.41M
    } else {
612
6
        if (cr->cram_flags & CRAM_FLAG_MATE_DOWNSTREAM) {
613
3
            r |= h->codecs[DS_NF]->encode(s, h->codecs[DS_NF],
614
3
                                          (char *)&cr->mate_line, 1);
615
3
        }
616
6
    }
617
618
    /* Aux tags */
619
9.41M
    if (CRAM_MAJOR_VERS(fd->version) == 1) {
620
0
        int j;
621
0
        uc = cr->ntags;
622
0
        r |= h->codecs[DS_TC]->encode(s, h->codecs[DS_TC], (char *)&uc, 1);
623
624
0
        for (j = 0; j < cr->ntags; j++) {
625
0
            uint32_t i32 = s->TN[cr->TN_idx + j]; // id
626
0
            r |= h->codecs[DS_TN]->encode(s, h->codecs[DS_TN], (char *)&i32, 1);
627
0
        }
628
9.41M
    } else {
629
9.41M
        r |= h->codecs[DS_TL]->encode(s, h->codecs[DS_TL], (char *)&cr->TL, 1);
630
9.41M
    }
631
632
    // qual
633
    // QS codec : Already stored in block[2].
634
635
    // features (diffs)
636
9.41M
    if (!(cr->flags & BAM_FUNMAP)) {
637
47.5k
        int prev_pos = 0, j;
638
639
47.5k
        r |= h->codecs[DS_FN]->encode(s, h->codecs[DS_FN],
640
47.5k
                                      (char *)&cr->nfeature, 1);
641
206k
        for (j = 0; j < cr->nfeature; j++) {
642
158k
            cram_feature *f = &s->features[cr->feature + j];
643
644
158k
            uc = f->X.code;
645
158k
            r |= h->codecs[DS_FC]->encode(s, h->codecs[DS_FC], (char *)&uc, 1);
646
158k
            i32 = f->X.pos - prev_pos;
647
158k
            r |= h->codecs[DS_FP]->encode(s, h->codecs[DS_FP], (char *)&i32, 1);
648
158k
            prev_pos = f->X.pos;
649
650
158k
            switch(f->X.code) {
651
                //char *seq;
652
653
5.96k
            case 'X':
654
                //fprintf(stderr, "    FC=%c FP=%d base=%d\n", f->X.code, i32, f->X.base);
655
656
5.96k
                uc = f->X.base;
657
5.96k
                r |= h->codecs[DS_BS]->encode(s, h->codecs[DS_BS],
658
5.96k
                                              (char *)&uc, 1);
659
5.96k
                break;
660
19.1k
            case 'S':
661
                // Already done
662
                //r |= h->codecs[DS_SC]->encode(s, h->codecs[DS_SC],
663
                //                              BLOCK_DATA(s->soft_blk) + f->S.seq_idx,
664
                //                              f->S.len);
665
666
                //if (CRAM_MAJOR_VERS(fd->version) >= 3) {
667
                //    r |= h->codecs[DS_BB]->encode(s, h->codecs[DS_BB],
668
                //                                  BLOCK_DATA(s->seqs_blk) + f->S.seq_idx,
669
                //                                  f->S.len);
670
                //}
671
19.1k
                break;
672
376
            case 'I':
673
                //seq = DSTRING_STR(s->seqs_ds) + f->S.seq_idx;
674
                //r |= h->codecs[DS_IN]->encode(s, h->codecs[DS_IN],
675
                //                           seq, f->S.len);
676
                //if (CRAM_MAJOR_VERS(fd->version) >= 3) {
677
                //    r |= h->codecs[DS_BB]->encode(s, h->codecs[DS_BB],
678
                //                                  BLOCK_DATA(s->seqs_blk) + f->I.seq_idx,
679
                //                                  f->I.len);
680
                //}
681
376
                break;
682
29
            case 'i':
683
29
                uc = f->i.base;
684
29
                r |= h->codecs[DS_BA]->encode(s, h->codecs[DS_BA],
685
29
                                              (char *)&uc, 1);
686
                //seq = DSTRING_STR(s->seqs_ds) + f->S.seq_idx;
687
                //r |= h->codecs[DS_IN]->encode(s, h->codecs[DS_IN],
688
                //                           seq, 1);
689
29
                break;
690
42.2k
            case 'D':
691
42.2k
                i32 = f->D.len;
692
42.2k
                r |= h->codecs[DS_DL]->encode(s, h->codecs[DS_DL],
693
42.2k
                                              (char *)&i32, 1);
694
42.2k
                break;
695
696
55.7k
            case 'B':
697
                //                  // Used when we try to store a non ACGTN base or an N
698
                //                  // that aligns against a non ACGTN reference
699
700
55.7k
                uc  = f->B.base;
701
55.7k
                r |= h->codecs[DS_BA]->encode(s, h->codecs[DS_BA],
702
55.7k
                                              (char *)&uc, 1);
703
704
                //                  Already added
705
                //                  uc  = f->B.qual;
706
                //                  r |= h->codecs[DS_QS]->encode(s, h->codecs[DS_QS],
707
                //                                           (char *)&uc, 1);
708
55.7k
                break;
709
710
2.23k
            case 'b':
711
                // string of bases
712
2.23k
                r |= h->codecs[DS_BB]->encode(s, h->codecs[DS_BB],
713
2.23k
                                              (char *)BLOCK_DATA(s->seqs_blk)
714
2.23k
                                                      + f->b.seq_idx,
715
2.23k
                                              f->b.len);
716
2.23k
                break;
717
718
68
            case 'Q':
719
                //                  Already added
720
                //                  uc  = f->B.qual;
721
                //                  r |= h->codecs[DS_QS]->encode(s, h->codecs[DS_QS],
722
                //                                           (char *)&uc, 1);
723
68
                break;
724
725
565
            case 'N':
726
565
                i32 = f->N.len;
727
565
                r |= h->codecs[DS_RS]->encode(s, h->codecs[DS_RS],
728
565
                                              (char *)&i32, 1);
729
565
                break;
730
731
479
            case 'P':
732
479
                i32 = f->P.len;
733
479
                r |= h->codecs[DS_PD]->encode(s, h->codecs[DS_PD],
734
479
                                              (char *)&i32, 1);
735
479
                break;
736
737
31.8k
            case 'H':
738
31.8k
                i32 = f->H.len;
739
31.8k
                r |= h->codecs[DS_HC]->encode(s, h->codecs[DS_HC],
740
31.8k
                                              (char *)&i32, 1);
741
31.8k
                break;
742
743
744
0
            default:
745
0
                hts_log_error("Unhandled feature code %c", f->X.code);
746
0
                return -1;
747
158k
            }
748
158k
        }
749
750
47.5k
        r |= h->codecs[DS_MQ]->encode(s, h->codecs[DS_MQ],
751
47.5k
                                      (char *)&cr->mqual, 1);
752
9.36M
    } else {
753
9.36M
        char *seq = (char *)BLOCK_DATA(s->seqs_blk) + cr->seq;
754
9.36M
        if (cr->len)
755
349k
            r |= h->codecs[DS_BA]->encode(s, h->codecs[DS_BA], seq, cr->len);
756
9.36M
    }
757
758
9.41M
    return r ? -1 : 0;
759
9.41M
}
760
761
762
/*
763
 * Applies various compression methods to specific blocks, depending on
764
 * known observations of how data series compress.
765
 *
766
 * Returns 0 on success
767
 *        -1 on failure
768
 */
769
34.7k
static int cram_compress_slice(cram_fd *fd, cram_container *c, cram_slice *s) {
770
34.7k
    int level = fd->level, i;
771
34.7k
    int method = 1<<GZIP | 1<<GZIP_RLE, methodF = method;
772
34.7k
    int v31_or_above = (fd->version >= (3<<8)+1);
773
774
    /* Compress the CORE Block too, with minimal zlib level */
775
34.7k
    if (level > 5 && s->block[0]->uncomp_size > 500)
776
0
        cram_compress_block2(fd, s, s->block[0], NULL, 1<<GZIP, 1);
777
778
34.7k
    if (fd->use_bz2)
779
0
        method |= 1<<BZIP2;
780
781
34.7k
    int method_rans   = (1<<RANS0) | (1<<RANS1);
782
34.7k
    int method_ranspr = method_rans;
783
784
34.7k
    if (fd->use_rans) {
785
34.7k
        method_ranspr = (1<<RANS_PR0)   | (1<<RANS_PR1);
786
34.7k
        if (level > 1)
787
34.7k
            method_ranspr |=
788
34.7k
                  (1<<RANS_PR64)  | (1<<RANS_PR9)
789
34.7k
                | (1<<RANS_PR128) | (1<<RANS_PR193);
790
34.7k
        if (level > 5)
791
0
            method_ranspr |= (1<<RANS_PR129) | (1<<RANS_PR192);
792
34.7k
    }
793
794
34.7k
    if (fd->use_rans) {
795
34.7k
        methodF |= v31_or_above ? method_ranspr : method_rans;
796
34.7k
        method  |= v31_or_above ? method_ranspr : method_rans;
797
34.7k
    }
798
799
34.7k
    int method_arith   = 0;
800
34.7k
    if (fd->use_arith) {
801
0
        method_arith = (1<<ARITH_PR0)   | (1<<ARITH_PR1);
802
0
        if (level > 1)
803
0
            method_arith |=
804
0
                  (1<<ARITH_PR64)  | (1<<ARITH_PR9)
805
0
                | (1<<ARITH_PR128) | (1<<ARITH_PR129)
806
0
                | (1<<ARITH_PR192) | (1u<<ARITH_PR193);
807
0
    }
808
34.7k
    if (fd->use_arith && v31_or_above) {
809
0
        methodF |= method_arith;
810
0
        method  |= method_arith;
811
0
    }
812
813
34.7k
    if (fd->use_lzma)
814
0
        method |= (1<<LZMA);
815
816
    /* Faster method for data series we only need entropy encoding on */
817
34.7k
    methodF = method & ~(1<<GZIP | 1<<BZIP2 | 1<<LZMA);
818
34.7k
    if (level >= 5) {
819
34.7k
        method |= 1<<GZIP_1;
820
34.7k
        methodF = method;
821
34.7k
    }
822
34.7k
    if (level == 1) {
823
0
        method &= ~(1<<GZIP);
824
0
        method |=   1<<GZIP_1;
825
0
        methodF = method;
826
0
    }
827
828
34.7k
    int qmethod  = method;
829
34.7k
    int qmethodF = method;
830
34.7k
    if (v31_or_above && fd->use_fqz) {
831
0
        qmethod  |= 1<<FQZ;
832
0
        qmethodF |= 1<<FQZ;
833
0
        if (fd->level > 4) {
834
0
            qmethod  |= 1<<FQZ_b;
835
0
            qmethodF |= 1<<FQZ_b;
836
0
        }
837
0
        if (fd->level > 6) {
838
0
            qmethod  |= (1<<FQZ_c) | (1<<FQZ_d);
839
0
            qmethodF |= (1<<FQZ_c) | (1<<FQZ_d);
840
0
        }
841
0
    }
842
843
34.7k
    pthread_mutex_lock(&fd->metrics_lock);
844
1.66M
    for (i = 0; i < DS_END; i++)
845
1.63M
        if (c->stats[i] && c->stats[i]->nvals > 16)
846
260
            fd->m[i]->unpackable = 1;
847
34.7k
    pthread_mutex_unlock(&fd->metrics_lock);
848
849
    /* Specific compression methods for certain block types */
850
34.7k
    if (cram_compress_block2(fd, s, s->block[DS_IN], fd->m[DS_IN], //IN (seq)
851
34.7k
                             method, level))
852
0
        return -1;
853
854
34.7k
    if (fd->level == 0) {
855
        /* Do nothing */
856
34.7k
    } else if (fd->level == 1) {
857
0
        if (cram_compress_block2(fd, s, s->block[DS_QS], fd->m[DS_QS],
858
0
                                 qmethodF, 1))
859
0
            return -1;
860
0
        for (i = DS_aux; i <= DS_aux_oz; i++) {
861
0
            if (s->block[i])
862
0
                if (cram_compress_block2(fd, s, s->block[i], fd->m[i],
863
0
                                         method, 1))
864
0
                    return -1;
865
0
        }
866
34.7k
    } else if (fd->level < 3) {
867
0
        if (cram_compress_block2(fd, s, s->block[DS_QS], fd->m[DS_QS],
868
0
                                 qmethod, 1))
869
0
            return -1;
870
0
        if (cram_compress_block2(fd, s, s->block[DS_BA], fd->m[DS_BA],
871
0
                                 method, 1))
872
0
            return -1;
873
0
        if (s->block[DS_BB])
874
0
            if (cram_compress_block2(fd, s, s->block[DS_BB], fd->m[DS_BB],
875
0
                                     method, 1))
876
0
                return -1;
877
0
        for (i = DS_aux; i <= DS_aux_oz; i++) {
878
0
            if (s->block[i])
879
0
                if (cram_compress_block2(fd, s, s->block[i], fd->m[i],
880
0
                                         method, level))
881
0
                    return -1;
882
0
        }
883
34.7k
    } else {
884
34.7k
        if (cram_compress_block2(fd, s, s->block[DS_QS], fd->m[DS_QS],
885
34.7k
                                 qmethod, level))
886
0
            return -1;
887
34.7k
        if (cram_compress_block2(fd, s, s->block[DS_BA], fd->m[DS_BA],
888
34.7k
                                 method, level))
889
0
            return -1;
890
34.7k
        if (s->block[DS_BB])
891
34.7k
            if (cram_compress_block2(fd, s, s->block[DS_BB], fd->m[DS_BB],
892
34.7k
                                     method, level))
893
0
                return -1;
894
347k
        for (i = DS_aux; i <= DS_aux_oz; i++) {
895
313k
            if (s->block[i])
896
0
                if (cram_compress_block2(fd, s, s->block[i], fd->m[i],
897
0
                                         method, level))
898
0
                    return -1;
899
313k
        }
900
34.7k
    }
901
902
    // NAME: best is generally xz, bzip2, zlib then rans1
903
34.7k
    int method_rn = method & ~(method_rans | method_ranspr | 1<<GZIP_RLE);
904
34.7k
    if (fd->version >= (3<<8)+1 && fd->use_tok)
905
34.7k
        method_rn |= fd->use_arith ? (1<<TOKA) : (1<<TOK3);
906
34.7k
    if (cram_compress_block2(fd, s, s->block[DS_RN], fd->m[DS_RN],
907
34.7k
                             method_rn, level))
908
0
        return -1;
909
910
    // NS shows strong local correlation as rearrangements are localised
911
34.7k
    if (s->block[DS_NS] && s->block[DS_NS] != s->block[0])
912
2.81k
        if (cram_compress_block2(fd, s, s->block[DS_NS], fd->m[DS_NS],
913
2.81k
                                 method, level))
914
0
            return -1;
915
916
917
    /*
918
     * Compress any auxiliary tags with their own per-tag metrics
919
     */
920
34.7k
    {
921
34.7k
        int i;
922
94.4k
        for (i = DS_END /*num_blk - naux_blk*/; i < s->hdr->num_blocks; i++) {
923
59.6k
            if (!s->block[i] || s->block[i] == s->block[0])
924
0
                continue;
925
926
59.6k
            if (s->block[i]->method != RAW)
927
0
                continue;
928
929
59.6k
            if (cram_compress_block2(fd, s, s->block[i], s->block[i]->m,
930
59.6k
                                     method, level))
931
0
                return -1;
932
59.6k
        }
933
34.7k
    }
934
935
    /*
936
     * Minimal compression of any block still uncompressed, bar CORE
937
     */
938
34.7k
    {
939
34.7k
        int i;
940
1.63M
        for (i = 1; i < s->hdr->num_blocks && i < DS_END; i++) {
941
1.59M
            if (!s->block[i] || s->block[i] == s->block[0])
942
1.32M
                continue;
943
944
274k
            if (s->block[i]->method != RAW)
945
10.6k
                continue;
946
947
264k
            if (cram_compress_block2(fd, s, s->block[i], fd->m[i],
948
264k
                                    methodF, level))
949
0
                return -1;
950
264k
        }
951
34.7k
    }
952
953
34.7k
    return 0;
954
34.7k
}
955
956
/*
957
 * Allocates a block associated with the cram codec associated with
958
 * data series ds_id or the internal codec_id (depending on codec
959
 * type).
960
 *
961
 * The ds_ids are what end up written to disk as an external block.
962
 * The c_ids are internal and used when daisy-chaining transforms
963
 * such as MAP and RLE.  These blocks are also allocated, but
964
 * are ephemeral in nature.  (The codecs themselves cannot allocate
965
 * these as the same codec pointer may be operating on multiple slices
966
 * if we're using a multi-slice container.)
967
 *
968
 * Returns 0 on success
969
 *        -1 on failure
970
 */
971
1.00M
static int cram_allocate_block(cram_codec *codec, cram_slice *s, int ds_id) {
972
1.00M
    if (!codec)
973
314k
        return 0;
974
975
693k
    switch(codec->codec) {
976
    // Codecs which are hard-coded to use the CORE block
977
0
    case E_GOLOMB:
978
432k
    case E_HUFFMAN:
979
433k
    case E_BETA:
980
433k
    case E_SUBEXP:
981
433k
    case E_GOLOMB_RICE:
982
433k
    case E_GAMMA:
983
433k
        codec->out = s->block[0];
984
433k
        break;
985
986
    // Codecs that emit directly to external blocks
987
155k
    case E_EXTERNAL:
988
155k
        if (!(s->block[ds_id] = cram_new_block(EXTERNAL, ds_id)))
989
0
            return -1;
990
155k
        codec->u.external.content_id = ds_id;
991
155k
        codec->out = s->block[ds_id];
992
155k
        break;
993
994
69.5k
    case E_BYTE_ARRAY_STOP: // Why no sub-codec?
995
69.5k
        if (!(s->block[ds_id] = cram_new_block(EXTERNAL, ds_id)))
996
0
            return -1;
997
69.5k
        codec->u.byte_array_stop.content_id = ds_id;
998
69.5k
        codec->out = s->block[ds_id];
999
69.5k
        break;
1000
1001
1002
    // Codecs that contain sub-codecs which may in turn emit to external blocks
1003
34.7k
    case E_BYTE_ARRAY_LEN: {
1004
34.7k
        cram_codec *bal = codec->u.e_byte_array_len.len_codec;
1005
34.7k
        if (cram_allocate_block(bal, s, bal->u.external.content_id))
1006
0
            return -1;
1007
34.7k
        bal = codec->u.e_byte_array_len.val_codec;
1008
34.7k
        if (cram_allocate_block(bal, s, bal->u.external.content_id))
1009
0
            return -1;
1010
1011
34.7k
        break;
1012
34.7k
    }
1013
1014
34.7k
    default:
1015
0
        break;
1016
693k
    }
1017
1018
693k
    return 0;
1019
693k
}
1020
1021
/*
1022
 * Encodes a single slice from a container
1023
 *
1024
 * Returns 0 on success
1025
 *        -1 on failure
1026
 */
1027
static int cram_encode_slice(cram_fd *fd, cram_container *c,
1028
                             cram_block_compression_hdr *h, cram_slice *s,
1029
34.7k
                             int embed_ref) {
1030
34.7k
    int rec, r = 0;
1031
34.7k
    int64_t last_pos;
1032
34.7k
    enum cram_DS_ID id;
1033
1034
    /*
1035
     * Slice external blocks:
1036
     * ID 0 => base calls (insertions, soft-clip)
1037
     * ID 1 => qualities
1038
     * ID 2 => names
1039
     * ID 3 => TS (insert size), NP (next frag)
1040
     * ID 4 => tag values
1041
     * ID 6 => tag IDs (TN), if CRAM_V1.0
1042
     * ID 7 => TD tag dictionary, if !CRAM_V1.0
1043
     */
1044
1045
    /* Create cram slice header */
1046
34.7k
    s->hdr->ref_base_id = embed_ref>0 && s->hdr->ref_seq_span > 0
1047
34.7k
        ? DS_ref
1048
34.7k
        : -1;
1049
1050
34.7k
    s->hdr->record_counter = c->num_records + c->record_counter;
1051
34.7k
    c->num_records += s->hdr->num_records;
1052
1053
34.7k
    int ntags = c->tags_used ? c->tags_used->n_occupied : 0;
1054
34.7k
    s->block = hts_calloc_ps(sizeof(s->block[0]), DS_END,
1055
34.7k
                             hts_prod_sat2(ntags, 2));
1056
34.7k
    s->hdr->block_content_ids = hts_malloc_p(sizeof(*s->hdr->block_content_ids),
1057
34.7k
                                             DS_END);
1058
34.7k
    if (!s->block || !s->hdr->block_content_ids)
1059
0
        return -1;
1060
1061
    // Create first fixed blocks, always external.
1062
    // CORE
1063
34.7k
    if (!(s->block[0] = cram_new_block(CORE, 0)))
1064
0
        return -1;
1065
1066
    // TN block for CRAM v1
1067
34.7k
    if (CRAM_MAJOR_VERS(fd->version) == 1) {
1068
0
        if (h->codecs[DS_TN]->codec == E_EXTERNAL) {
1069
0
            if (!(s->block[DS_TN] = cram_new_block(EXTERNAL,DS_TN))) return -1;
1070
0
            h->codecs[DS_TN]->u.external.content_id = DS_TN;
1071
0
        } else {
1072
0
            s->block[DS_TN] = s->block[0];
1073
0
        }
1074
0
    }
1075
1076
    // Embedded reference
1077
34.7k
    if (embed_ref>0) {
1078
14.6k
        if (!(s->block[DS_ref] = cram_new_block(EXTERNAL, DS_ref)))
1079
0
            return -1;
1080
14.6k
        s->ref_id = DS_ref; // needed?
1081
14.6k
        BLOCK_APPEND(s->block[DS_ref],
1082
14.6k
                     c->ref + s->hdr->ref_seq_start - c->ref_start,
1083
14.6k
                     s->hdr->ref_seq_span);
1084
14.6k
    }
1085
1086
    /*
1087
     * All the data-series blocks if appropriate.
1088
     */
1089
973k
    for (id = DS_QS; id < DS_TN; id++) {
1090
939k
        if (cram_allocate_block(h->codecs[id], s, id) < 0)
1091
0
            return -1;
1092
939k
    }
1093
1094
    /*
1095
     * Add in the external tag blocks too.
1096
     */
1097
34.7k
    if (c->tags_used) {
1098
34.7k
        int n;
1099
34.7k
        s->hdr->num_blocks = DS_END;
1100
94.4k
        for (n = 0; n < s->naux_block; n++) {
1101
59.6k
            s->block[s->hdr->num_blocks++] = s->aux_block[n];
1102
59.6k
            s->aux_block[n] = NULL;
1103
59.6k
        }
1104
34.7k
    }
1105
1106
    /* Encode reads */
1107
34.7k
    last_pos = s->hdr->ref_seq_start;
1108
9.44M
    for (rec = 0; rec < s->hdr->num_records; rec++) {
1109
9.41M
        cram_record *cr = &s->crecs[rec];
1110
9.41M
        if (cram_encode_slice_read(fd, c, h, s, cr, &last_pos) == -1)
1111
0
            return -1;
1112
9.41M
    }
1113
1114
34.7k
    s->block[0]->uncomp_size = s->block[0]->byte + (s->block[0]->bit < 7);
1115
34.7k
    s->block[0]->comp_size = s->block[0]->uncomp_size;
1116
1117
    // Make sure the fixed blocks point to the correct sources
1118
34.7k
    if (s->block[DS_IN]) cram_free_block(s->block[DS_IN]);
1119
34.7k
    s->block[DS_IN] = s->base_blk; s->base_blk = NULL;
1120
34.7k
    if (s->block[DS_QS]) cram_free_block(s->block[DS_QS]);
1121
34.7k
    s->block[DS_QS] = s->qual_blk; s->qual_blk = NULL;
1122
34.7k
    if (s->block[DS_RN]) cram_free_block(s->block[DS_RN]);
1123
34.7k
    s->block[DS_RN] = s->name_blk; s->name_blk = NULL;
1124
34.7k
    if (s->block[DS_SC]) cram_free_block(s->block[DS_SC]);
1125
34.7k
    s->block[DS_SC] = s->soft_blk; s->soft_blk = NULL;
1126
1127
    // Finalise any data transforms.
1128
973k
    for (id = DS_QS; id < DS_TN; id++) {
1129
939k
       if (h->codecs[id] && h->codecs[id]->flush)
1130
0
           h->codecs[id]->flush(h->codecs[id]);
1131
939k
    }
1132
1133
    // Ensure block sizes are up to date.
1134
1.69M
    for (id = 1; id < s->hdr->num_blocks; id++) {
1135
1.65M
        if (!s->block[id] || s->block[id] == s->block[0])
1136
1.32M
            continue;
1137
1138
334k
        if (s->block[id]->uncomp_size == 0)
1139
334k
            BLOCK_UPLEN(s->block[id]);
1140
334k
    }
1141
1142
    // Compress it all
1143
34.7k
    if (cram_compress_slice(fd, c, s) == -1)
1144
0
        return -1;
1145
1146
    // Collapse empty blocks and create hdr_block
1147
34.7k
    {
1148
34.7k
        int i, j;
1149
1150
34.7k
        int32_t *bids = hts_realloc_p(s->hdr->block_content_ids,
1151
34.7k
                                      sizeof(*s->hdr->block_content_ids),
1152
34.7k
                                      s->hdr->num_blocks);
1153
34.7k
        if (!bids)
1154
0
            return -1;
1155
34.7k
        s->hdr->block_content_ids = bids;
1156
1157
1.69M
        for (i = j = 1; i < s->hdr->num_blocks; i++) {
1158
1.65M
            if (!s->block[i] || s->block[i] == s->block[0])
1159
1.32M
                continue;
1160
334k
            if (s->block[i]->uncomp_size == 0) {
1161
165k
                cram_free_block(s->block[i]);
1162
165k
                s->block[i] = NULL;
1163
165k
                continue;
1164
165k
            }
1165
169k
            s->block[j] = s->block[i];
1166
169k
            s->hdr->block_content_ids[j-1] = s->block[i]->content_id;
1167
169k
            j++;
1168
169k
        }
1169
34.7k
        s->hdr->num_content_ids = j-1;
1170
34.7k
        s->hdr->num_blocks = j;
1171
1172
34.7k
        if (!(s->hdr_block = cram_encode_slice_header(fd, s)))
1173
187
            return -1;
1174
34.7k
    }
1175
1176
34.5k
    return r ? -1 : 0;
1177
1178
0
 block_err:
1179
0
    return -1;
1180
34.7k
}
1181
1182
9.41M
static inline const char *bam_data_end(bam1_t *b) {
1183
9.41M
    return (const char *)b->data + b->l_data;
1184
9.41M
}
1185
1186
/*
1187
 * A bounds checking version of bam_aux2i.
1188
 */
1189
5
static inline int bam_aux2i_end(const uint8_t *aux, const uint8_t *aux_end) {
1190
5
    int type = *aux++;
1191
5
    switch (type) {
1192
0
        case 'c':
1193
0
            if (aux_end - aux < 1) {
1194
0
                errno = EINVAL;
1195
0
                return 0;
1196
0
            }
1197
0
            return *(int8_t *)aux;
1198
0
        case 'C':
1199
0
            if (aux_end - aux < 1) {
1200
0
                errno = EINVAL;
1201
0
                return 0;
1202
0
            }
1203
0
            return *aux;
1204
0
        case 's':
1205
0
            if (aux_end - aux < 2) {
1206
0
                errno = EINVAL;
1207
0
                return 0;
1208
0
            }
1209
0
            return le_to_i16(aux);
1210
0
        case 'S':
1211
0
            if (aux_end - aux < 2) {
1212
0
                errno = EINVAL;
1213
0
                return 0;
1214
0
            }
1215
0
            return le_to_u16(aux);
1216
0
        case 'i':
1217
0
            if (aux_end - aux < 4) {
1218
0
                errno = EINVAL;
1219
0
                return 0;
1220
0
            }
1221
0
            return le_to_i32(aux);
1222
0
        case 'I':
1223
0
            if (aux_end - aux < 4) {
1224
0
                errno = EINVAL;
1225
0
                return 0;
1226
0
            }
1227
0
            return le_to_u32(aux);
1228
5
        default:
1229
5
            errno = EINVAL;
1230
5
    }
1231
5
    return 0;
1232
5
}
1233
1234
/*
1235
 * Returns the number of expected read names for this record.
1236
 */
1237
0
static int expected_template_count(bam_seq_t *b) {
1238
0
    int expected = bam_flag(b) & BAM_FPAIRED ? 2 : 1;
1239
1240
0
    uint8_t *TC = (uint8_t *)bam_aux_get(b, "TC");
1241
0
    if (TC) {
1242
0
        int n = bam_aux2i_end(TC, (uint8_t *)bam_data_end(b));
1243
0
        if (expected < n)
1244
0
            expected = n;
1245
0
    }
1246
1247
0
    if (!TC && bam_aux_get(b, "SA")) {
1248
        // We could count the semicolons, but we'd have to do this for
1249
        // read1, read2 and read(not-1-or-2) combining the results
1250
        // together.  This is a cheap and safe alternative for now.
1251
0
        expected = INT_MAX;
1252
0
    }
1253
1254
0
    return expected;
1255
0
}
1256
1257
/*
1258
 * Lossily reject read names.
1259
 *
1260
 * The rule here is that if all reads for this template reside in the
1261
 * same slice then we can lose the name.  Otherwise we keep them as we
1262
 * do not know when (or if) the other reads will turn up.
1263
 *
1264
 * Note there may be only 1 read (non-paired library) or more than 2
1265
 * reads (paired library with supplementary reads), or other weird
1266
 * setups.  We need to know how many are expected.  Ways to guess:
1267
 *
1268
 * - Flags (0x1 - has > 1 read)
1269
 * - TC aux field (not mandatory)
1270
 * - SA tags (count semicolons, NB per fragment so sum - hard)
1271
 * - RNEXT/PNEXT uniqueness count. (not implemented, tricky)
1272
 *
1273
 * Returns 0 on success
1274
 *        -1 on failure
1275
 */
1276
static int lossy_read_names(cram_fd *fd, cram_container *c, cram_slice *s,
1277
36.6k
                            int bam_start) {
1278
36.6k
    int r1, r2, ret = -1;
1279
1280
    // Initialise cram_flags
1281
9.45M
    for (r2 = 0; r2 < s->hdr->num_records; r2++)
1282
9.42M
        s->crecs[r2].cram_flags = 0;
1283
1284
36.6k
    if (!fd->lossy_read_names)
1285
36.6k
        return 0;
1286
1287
0
    khash_t(m_s2u64) *names = kh_init(m_s2u64);
1288
0
    if (!names)
1289
0
        goto fail;
1290
1291
    // 1: Iterate through names to count frequency
1292
0
    for (r1 = bam_start, r2 = 0; r2 < s->hdr->num_records; r1++, r2++) {
1293
        //cram_record *cr = &s->crecs[r2];
1294
0
        bam_seq_t *b = &c->bams[r1];
1295
0
        khint_t k;
1296
0
        int n;
1297
0
        uint64_t e;
1298
0
        union {
1299
0
            uint64_t i64;
1300
0
            struct {
1301
0
                int32_t e,c; // expected & observed counts.
1302
0
            } counts;
1303
0
        } u;
1304
1305
0
        e = expected_template_count(b);
1306
0
        u.counts.e = e; u.counts.c = 1;
1307
1308
0
        k = kh_put(m_s2u64, names, bam_name(b), &n);
1309
0
        if (n == -1)
1310
0
            goto fail;
1311
1312
0
        if (n == 0) {
1313
            // not a new name
1314
0
            u.i64 = kh_val(names, k);
1315
0
            if (u.counts.e != e) {
1316
                // different expectation or already hit the max
1317
                //fprintf(stderr, "Err computing no. %s recs\n", bam_name(b));
1318
0
                kh_val(names, k) = 0;
1319
0
            } else {
1320
0
                u.counts.c++;
1321
0
                if (u.counts.e == u.counts.c) {
1322
                    // Reached expected count.
1323
0
                    kh_val(names, k) = -1;
1324
0
                } else {
1325
0
                    kh_val(names, k) = u.i64;
1326
0
                }
1327
0
            }
1328
0
        } else {
1329
            // new name
1330
0
            kh_val(names, k) = u.i64;
1331
0
        }
1332
0
    }
1333
1334
    // 2: Remove names if all present (hd.i == -1)
1335
0
    for (r1 = bam_start, r2 = 0; r2 < s->hdr->num_records; r1++, r2++) {
1336
0
        cram_record *cr = &s->crecs[r2];
1337
0
        bam_seq_t *b = &c->bams[r1];
1338
0
        khint_t k;
1339
1340
0
        k = kh_get(m_s2u64, names, bam_name(b));
1341
1342
0
        if (k == kh_end(names))
1343
0
            goto fail;
1344
1345
0
        if (kh_val(names, k) == -1)
1346
0
            cr->cram_flags = CRAM_FLAG_DISCARD_NAME;
1347
0
    }
1348
1349
0
    ret = 0;
1350
0
 fail: // ret==-1
1351
1352
0
    if (names)
1353
0
        kh_destroy(m_s2u64, names);
1354
1355
0
    return ret;
1356
0
}
1357
1358
/*
1359
 * Adds the reading names.  We do this here as a separate pass rather
1360
 * than per record in the process_one_read calls as that function can
1361
 * go back and change the CRAM_FLAG_DETACHED status of a previously
1362
 * processed read if it subsequently determines the TLEN field is
1363
 * incorrect.  Given DETACHED reads always try to decode read names,
1364
 * we need to know their status before generating the read-name block.
1365
 *
1366
 * Output is an update s->name_blk, and cr->name / cr->name_len
1367
 * fields.
1368
 */
1369
static int add_read_names(cram_fd *fd, cram_container *c, cram_slice *s,
1370
34.8k
                          int bam_start) {
1371
34.8k
    int r1, r2;
1372
34.8k
    int keep_names = !fd->lossy_read_names;
1373
1374
34.8k
    for (r1 = bam_start, r2 = 0;
1375
9.45M
         r1 < c->curr_c_rec && r2 < s->hdr->num_records;
1376
9.41M
         r1++, r2++) {
1377
9.41M
        cram_record *cr = &s->crecs[r2];
1378
9.41M
        bam_seq_t *b = &c->bams[r1];
1379
1380
9.41M
        cr->name        = BLOCK_SIZE(s->name_blk);
1381
9.41M
        if ((cr->cram_flags & CRAM_FLAG_DETACHED) || keep_names) {
1382
            // In CRAMv4 we stored read name of "\0" if we the read is
1383
            // paired in this slide (CRAM_FLAG_MATE_DOWNSTREAM).
1384
            // This accounted for 95% of the space saving (and a
1385
            // small speed increase) when running in normal mode.
1386
            // We could reinstigate this in a potential v3.2 maybe.
1387
9.41M
            BLOCK_APPEND(s->name_blk, bam_name(b), bam_name_len(b));
1388
9.41M
            cr->name_len    = bam_name_len(b);
1389
9.41M
        } else {
1390
            // Can only discard duplicate names if not detached
1391
0
            cr->name_len = 0;
1392
0
        }
1393
1394
9.41M
        if (cram_stats_add(c->stats[DS_RN], cr->name_len) < 0)
1395
0
            goto block_err;
1396
9.41M
    }
1397
1398
34.8k
    return 0;
1399
1400
0
 block_err:
1401
0
    return -1;
1402
34.8k
}
1403
1404
// CRAM version >= 3.1
1405
56.7k
#define CRAM_ge31(v) ((v) >= 0x301)
1406
1407
// Returns the next cigar op code: one of the BAM_C* codes,
1408
// or -1 if no more are present.
1409
static inline
1410
int next_cigar_op(uint32_t *cigar, uint32_t ncigar, int *skip, int *spos,
1411
65.4k
                  uint32_t *cig_ind, uint32_t *cig_op, uint32_t *cig_len) {
1412
71.8k
    for(;;) {
1413
127k
        while (*cig_len == 0) {
1414
55.4k
            if (*cig_ind < ncigar) {
1415
55.1k
                *cig_op  = cigar[*cig_ind] & BAM_CIGAR_MASK;
1416
55.1k
                *cig_len = cigar[*cig_ind] >> BAM_CIGAR_SHIFT;
1417
55.1k
                (*cig_ind)++;
1418
55.1k
            } else {
1419
249
                return -1;
1420
249
            }
1421
55.4k
        }
1422
1423
71.6k
        if (skip[*cig_op]) {
1424
6.41k
            *spos += (bam_cigar_type(*cig_op)&1) * *cig_len;
1425
6.41k
            *cig_len = 0;
1426
6.41k
            continue;
1427
6.41k
        }
1428
1429
65.2k
        (*cig_len)--;
1430
65.2k
        break;
1431
71.6k
    }
1432
1433
65.2k
    return *cig_op;
1434
65.4k
}
1435
1436
typedef uint8_t hist_t;
1437
31.9k
#define MAX_HIST_T UINT8_MAX
1438
1439
// Ensure ref and hist are large enough.
1440
static inline int extend_ref(char **ref, hist_t (**hist)[6], hts_pos_t pos,
1441
                             hts_pos_t ref_start, hts_pos_t *ref_end,
1442
359k
                             hts_pos_t *ref_end_alloc) {
1443
359k
    if (*ref_end < pos && pos < *ref_end_alloc)
1444
6.46k
        *ref_end = pos;
1445
359k
    if (pos < ref_start)
1446
141
        return -1;
1447
359k
    if (pos < *ref_end_alloc)
1448
341k
        return 0;
1449
1450
    // realloc
1451
17.1k
    if (pos - ref_start > UINT_MAX)
1452
145
        return -2; // protect overflow in new_end calculation
1453
1454
17.0k
    hts_pos_t old_end = *ref_end_alloc ? *ref_end_alloc : ref_start;
1455
17.0k
    hts_pos_t new_end = ref_start + 1000 + (pos-ref_start)*1.5;
1456
1457
    // Refuse to work on excessively large blocks.
1458
    // We'll just switch to referenceless encoding, which is probably better
1459
    // here as this must be very sparse data anyway.
1460
17.0k
    if (new_end - ref_start > UINT_MAX/sizeof(**hist)/8)
1461
320
        return -2;
1462
1463
16.6k
    char *tmp = realloc(*ref, new_end-ref_start+1);
1464
16.6k
    if (!tmp)
1465
0
        return -1;
1466
16.6k
    *ref = tmp;
1467
1468
    // hist[6] = {A C G T N total}
1469
16.6k
    hist_t (*tmp_hist)[6] = hts_realloc_p(**hist, sizeof(**hist),
1470
16.6k
                                          new_end - ref_start);
1471
16.6k
    if (!tmp_hist)
1472
0
        return -1;
1473
16.6k
    *hist = tmp_hist;
1474
16.6k
    *ref_end_alloc = new_end;
1475
1476
    // initialise
1477
16.6k
    old_end -= ref_start;
1478
16.6k
    new_end -= ref_start;
1479
16.6k
    memset(&(*ref)[old_end],  0,  new_end-old_end);
1480
16.6k
    memset(&(*hist)[old_end], 0, (new_end-old_end)*sizeof(**hist));
1481
1482
16.6k
    if (*ref_end < pos)
1483
16.5k
        *ref_end = pos;
1484
1485
16.6k
    return 0;
1486
16.6k
}
1487
1488
// Walk through MD + seq to generate ref
1489
// Returns 1 on success, <0 on failure
1490
static int cram_add_to_ref_MD(bam1_t *b, char **ref, hist_t (**hist)[6],
1491
                              hts_pos_t ref_start, hts_pos_t *ref_end,
1492
38.3k
                              hts_pos_t *ref_end_alloc, const uint8_t *MD) {
1493
38.3k
    uint8_t *seq = bam_get_seq(b);
1494
38.3k
    uint32_t *cigar = bam_get_cigar(b);
1495
38.3k
    uint32_t ncigar = b->core.n_cigar;
1496
38.3k
    uint32_t cig_op = 0, cig_len = 0, cig_ind = 0;
1497
1498
    // End position of the sequence on the reference.
1499
38.3k
    hts_pos_t rlen = bam_cigar2rlen(b->core.n_cigar, bam_get_cigar(b));
1500
38.3k
    hts_pos_t rseq_end = b->core.pos + (rlen ? rlen : b->core.l_qseq);
1501
1502
    // No sequence means extend based on CIGAR instead
1503
38.3k
    if (!b->core.l_qseq && extend_ref(ref, hist, rseq_end,
1504
13.2k
                                      ref_start, ref_end, ref_end_alloc) < 0)
1505
6
        return -1;
1506
1507
38.3k
    int iseq = 0, next_op;
1508
38.3k
    hts_pos_t iref = b->core.pos - ref_start;
1509
1510
    // Skip INS, REF_SKIP, *CLIP, PAD. and BACK.
1511
38.3k
    static int cig_skip[16] = {0,1,0,1,1,1,1,0,0,1,1,1,1,1,1,1};
1512
95.5k
    while (iseq < b->core.l_qseq && *MD) {
1513
61.3k
        if (isdigit(*MD)) {
1514
            // match
1515
12.0k
            int overflow = 0;
1516
12.0k
            int len = hts_str2uint((char *)MD, (char **)&MD, 31, &overflow);
1517
12.0k
            if (overflow ||
1518
11.8k
                extend_ref(ref, hist, iref+ref_start + len,
1519
11.8k
                           ref_start, ref_end, ref_end_alloc) < 0)
1520
365
                return -1;
1521
17.4k
            while (iseq < b->core.l_qseq && len) {
1522
                // rewrite to have internal loops?
1523
5.98k
                if ((next_op = next_cigar_op(cigar, ncigar, cig_skip,
1524
5.98k
                                             &iseq, &cig_ind, &cig_op,
1525
5.98k
                                             &cig_len)) < 0)
1526
31
                    return -1;
1527
1528
5.95k
                if (next_op != BAM_CMATCH &&
1529
323
                    next_op != BAM_CEQUAL) {
1530
119
                    hts_log_info("MD:Z and CIGAR are incompatible for "
1531
119
                                 "record %s", bam_get_qname(b));
1532
119
                    return -1;
1533
119
                }
1534
1535
                // Short-cut loop over same cigar op for efficiency
1536
5.83k
                cig_len++;
1537
31.3k
                do {
1538
31.3k
                    cig_len--;
1539
31.3k
                    (*ref)[iref++] = seq_nt16_str[bam_seqi(seq, iseq)];
1540
31.3k
                    iseq++;
1541
31.3k
                    len--;
1542
31.3k
                } while (cig_len && iseq < b->core.l_qseq && len);
1543
5.83k
            }
1544
11.5k
            if (len > 0)
1545
2.92k
                return -1; // MD is longer than seq
1546
49.3k
        } else if (*MD == '^') {
1547
            // deletion
1548
7.63k
            MD++;
1549
17.7k
            while (isalpha(*MD)) {
1550
17.7k
                if (extend_ref(ref, hist, iref+ref_start, ref_start,
1551
17.7k
                               ref_end, ref_end_alloc) < 0)
1552
3
                    return -1;
1553
17.7k
                if ((next_op = next_cigar_op(cigar, ncigar, cig_skip,
1554
17.7k
                                             &iseq, &cig_ind, &cig_op,
1555
17.7k
                                             &cig_len)) < 0)
1556
102
                    return -1;
1557
1558
17.6k
                if (next_op != BAM_CDEL) {
1559
46
                    hts_log_info("MD:Z and CIGAR are incompatible");
1560
46
                    return -1;
1561
46
                }
1562
1563
17.6k
                (*ref)[iref++] = *MD++ & ~0x20;
1564
17.6k
            }
1565
41.7k
        } else {
1566
            // substitution
1567
41.7k
            if (extend_ref(ref, hist, iref+ref_start, ref_start, ref_end,
1568
41.7k
                           ref_end_alloc) < 0)
1569
8
                return -1;
1570
41.7k
            if ((next_op = next_cigar_op(cigar, ncigar, cig_skip,
1571
41.7k
                                         &iseq, &cig_ind, &cig_op,
1572
41.7k
                                         &cig_len)) < 0)
1573
116
                return -1;
1574
1575
41.6k
            if (next_op != BAM_CMATCH && next_op != BAM_CDIFF) {
1576
461
                hts_log_info("MD:Z and CIGAR are incompatible");
1577
461
                return -1;
1578
461
            }
1579
1580
41.1k
            (*ref)[iref++] = *MD++ & ~0x20;
1581
41.1k
            iseq++;
1582
41.1k
        }
1583
61.3k
    }
1584
1585
34.2k
    return 1;
1586
38.3k
}
1587
1588
// Append a sequence to a ref/consensus structure.
1589
// We maintain both an absolute refefence (ACGTN where MD:Z is
1590
// present) and a 5-way frequency array for when no MD:Z is known.
1591
// We then subsequently convert the 5-way frequencies to a consensus
1592
// ref in a second pass.
1593
//
1594
// Returns >=0 on success,
1595
//         -1 on failure (eg inconsistent data)
1596
static int cram_add_to_ref(bam1_t *b, char **ref, hist_t (**hist)[6],
1597
                           hts_pos_t ref_start, hts_pos_t *ref_end,
1598
42.1k
                           hts_pos_t *ref_end_alloc) {
1599
42.1k
    const uint8_t *MD = bam_aux_get(b, "MD");
1600
42.1k
    int ret = 0;
1601
42.1k
    if (MD && *MD == 'Z') {
1602
        // We can use MD to directly compute the reference
1603
38.3k
        int ret = cram_add_to_ref_MD(b, ref, hist, ref_start, ref_end,
1604
38.3k
                                     ref_end_alloc, MD+1);
1605
1606
38.3k
        if (ret > 0)
1607
34.2k
            return ret;
1608
38.3k
    }
1609
1610
    // Otherwise we just use SEQ+CIGAR and build a consensus which we later
1611
    // turn into a fake reference
1612
7.95k
    uint32_t *cigar = bam_get_cigar(b);
1613
7.95k
    uint32_t ncigar = b->core.n_cigar;
1614
7.95k
    uint32_t i, j;
1615
7.95k
    hts_pos_t iseq = 0, iref = b->core.pos - ref_start;
1616
7.95k
    uint8_t *seq = bam_get_seq(b);
1617
324k
    for (i = 0; i < ncigar; i++) {
1618
317k
        switch (bam_cigar_op(cigar[i])) {
1619
6.08k
        case BAM_CSOFT_CLIP:
1620
16.6k
        case BAM_CINS:
1621
16.6k
            iseq += bam_cigar_oplen(cigar[i]);
1622
16.6k
            break;
1623
1624
245k
        case BAM_CMATCH:
1625
247k
        case BAM_CEQUAL:
1626
247k
        case BAM_CDIFF: {
1627
247k
            int len = bam_cigar_oplen(cigar[i]);
1628
            // Maps an nt16 (A=1 C=2 G=4 T=8 bits) to 0123 plus N=4
1629
247k
            static uint8_t L16[16] = {4,0,1,4, 2,4,4,4, 3,4,4,4, 4,4,4,4};
1630
1631
247k
            if (extend_ref(ref, hist, iref+ref_start + len,
1632
247k
                           ref_start, ref_end, ref_end_alloc) < 0)
1633
20
                return -1;
1634
247k
            if (iseq + len <= b->core.l_qseq) {
1635
                // Nullify failed MD:Z if appropriate
1636
6.12k
                if (ret < 0)
1637
0
                    memset(&(*ref)[iref], 0, len);
1638
1639
38.0k
                for (j = 0; j < len; j++, iref++, iseq++) {
1640
31.9k
                    if ((*hist)[iref][5] < MAX_HIST_T) {
1641
31.9k
                        (*hist)[iref][5]++;
1642
31.9k
                        (*hist)[iref][L16[bam_seqi(seq, iseq)]]++;
1643
31.9k
                    }
1644
                    // else overly deep and compute the consensus on the
1645
                    // first alignments only.  Equivalent to a (biased)
1646
                    // subsampling of data.  We could unbias it by selectively
1647
                    // discarding, but it's likely unnecessary.
1648
31.9k
                }
1649
241k
            } else {
1650
                // Probably a 2ndary read with seq "*"
1651
241k
                iseq += len;
1652
241k
                iref += len;
1653
241k
            }
1654
247k
            break;
1655
247k
        }
1656
1657
11.0k
        case BAM_CDEL:
1658
11.3k
        case BAM_CREF_SKIP: {
1659
11.3k
            int len = bam_cigar_oplen(cigar[i]);
1660
11.3k
            if (extend_ref(ref, hist, iref+ref_start + len,
1661
11.3k
                           ref_start, ref_end, ref_end_alloc) < 0)
1662
147
                return -1;
1663
11.2k
            iref += bam_cigar_oplen(cigar[i]);
1664
11.2k
            break;
1665
11.3k
        }
1666
317k
        }
1667
317k
    }
1668
1669
7.78k
    return 1;
1670
7.95k
}
1671
1672
// Automatically generates the reference and stashed it in c->ref, also
1673
// setting c->ref_start and c->ref_end.
1674
//
1675
// If we have MD:Z tags then we use them to directly infer the reference,
1676
// along with SEQ + CIGAR.  Otherwise we use SEQ/CIGAR only to build up
1677
// a consensus and then assume the reference as the majority rule.
1678
//
1679
// In this latter scenario we need to be wary of auto-generating MD and NM
1680
// during decode, but that's handled elsewhere via an additional aux tag.
1681
//
1682
// Returns 0 on success,
1683
//        -1 on failure
1684
15.8k
static int cram_generate_reference(cram_container *c, cram_slice *s, int r1) {
1685
    // TODO: if we can find an external reference then use it, even if the
1686
    // user told us to do embed_ref=2.
1687
15.8k
    char *ref = NULL;
1688
15.8k
    hist_t (*hist)[6] = NULL;
1689
15.8k
    hts_pos_t ref_start = c->bams[r1].core.pos, ref_end = 0,
1690
15.8k
        ref_end_alloc = 0;
1691
15.8k
    if (ref_start < 0)
1692
8
        return -1; // cannot build consensus from unmapped data
1693
1694
    // initial allocation
1695
15.8k
    if (extend_ref(&ref, &hist,
1696
15.8k
                   c->bams[r1 + s->hdr->num_records-1].core.pos +
1697
15.8k
                   c->bams[r1 + s->hdr->num_records-1].core.l_qseq,
1698
15.8k
                   ref_start, &ref_end, &ref_end_alloc) < 0)
1699
258
        return -1;
1700
1701
15.5k
    size_t nbase = 0;
1702
1703
    // Add each bam file to the reference/consensus arrays
1704
15.5k
    int r2;
1705
15.5k
    hts_pos_t last_pos = -1;
1706
57.5k
    for (r2 = 0; r1 < c->curr_c_rec && r2 < s->hdr->num_records; r1++, r2++) {
1707
42.1k
        if (c->bams[r1].core.pos < last_pos) {
1708
33
            hts_log_error("Cannot build reference with unsorted data");
1709
33
            goto err;
1710
33
        }
1711
42.1k
        last_pos = c->bams[r1].core.pos;
1712
42.1k
        nbase += c->bams[r1].core.l_qseq;
1713
42.1k
        if (cram_add_to_ref(&c->bams[r1], &ref, &hist, ref_start, &ref_end,
1714
42.1k
                            &ref_end_alloc) < 0)
1715
167
            goto err;
1716
42.1k
    }
1717
1718
    // Skip if the reference is mostly N due to very sparse data or
1719
    // huge deletions / ref-skips.
1720
15.3k
    if (nbase < 0.01 * (ref_end - ref_start))
1721
631
        goto err;
1722
1723
    // Compute the consensus
1724
14.7k
    hts_pos_t i;
1725
1.57M
    for (i = 0; i < ref_end-ref_start; i++) {
1726
1.56M
        if (!ref[i]) {
1727
1.55M
            hist_t max_v = 0, max_j = 4, j;
1728
7.75M
            for (j = 0; j < 4; j++)
1729
                // don't call N (j==4) unless no coverage
1730
6.20M
                if (max_v < hist[i][j])
1731
59
                    max_v = hist[i][j], max_j = j;
1732
1.55M
            ref[i] = "ACGTN"[max_j];
1733
1.55M
        }
1734
1.56M
    }
1735
14.7k
    free(hist);
1736
1737
    // Put the reference in place so it appears to be an external
1738
    // ref file.
1739
14.7k
    c->ref       = ref;
1740
14.7k
    c->ref_start = ref_start+1;
1741
14.7k
    c->ref_end   = ref_end+1;
1742
14.7k
    c->ref_free  = 1;
1743
1744
14.7k
    return 0;
1745
1746
831
 err:
1747
831
    free(ref);
1748
831
    free(hist);
1749
831
    return -1;
1750
15.3k
}
1751
1752
// Check if the SQ M5 tag matches the reference we've loaded.
1753
0
static int validate_md5(cram_fd *fd, int ref_id) {
1754
0
    if (fd->ignore_md5 || ref_id < 0 || ref_id >= fd->refs->nref)
1755
0
        return 0;
1756
1757
    // Have we already checked this ref?
1758
0
    if (fd->refs->ref_id[ref_id]->validated_md5)
1759
0
        return 0;
1760
1761
    // Check if we have the MD5 known.
1762
    // We should, but maybe we're using embedded references?
1763
0
    sam_hrecs_t *hrecs = fd->header->hrecs;
1764
0
    sam_hrec_type_t *ty = sam_hrecs_find_type_id(hrecs, "SQ", "SN",
1765
0
                                                 hrecs->ref[ref_id].name);
1766
0
    if (!ty)
1767
0
        return 0;
1768
1769
0
    sam_hrec_tag_t *m5tag = sam_hrecs_find_key(ty, "M5", NULL);
1770
0
    if (!m5tag)
1771
0
        return 0;
1772
1773
    // It's known, so compute md5 on the loaded reference sequence.
1774
0
    char *ref = fd->refs->ref_id[ref_id]->seq;
1775
0
    int64_t len = fd->refs->ref_id[ref_id]->length;
1776
0
    hts_md5_context *md5;
1777
0
    char unsigned buf[16];
1778
0
    char buf2[33];
1779
1780
0
    if (!(md5 = hts_md5_init()))
1781
0
        return -1;
1782
0
    hts_md5_update(md5, ref, len);
1783
0
    hts_md5_final(buf, md5);
1784
0
    hts_md5_destroy(md5);
1785
0
    hts_md5_hex(buf2, buf);
1786
1787
    // Compare it to header @SQ M5 tag
1788
0
    if (strcmp(m5tag->str+3, buf2)) {
1789
0
        hts_log_error("SQ header M5 tag discrepancy for reference '%s'",
1790
0
                      hrecs->ref[ref_id].name);
1791
0
        hts_log_error("Please use the correct reference, or "
1792
0
                      "consider using embed_ref=2");
1793
0
        return -1;
1794
0
    }
1795
0
    fd->refs->ref_id[ref_id]->validated_md5 = 1;
1796
1797
0
    return 0;
1798
0
}
1799
1800
/*
1801
 * Encodes all slices in a container into blocks.
1802
 * Returns 0 on success
1803
 *        -1 on failure
1804
 */
1805
35.6k
int cram_encode_container(cram_fd *fd, cram_container *c) {
1806
35.6k
    int i, j, slice_offset;
1807
35.6k
    cram_block_compression_hdr *h = c->comp_hdr;
1808
35.6k
    cram_block *c_hdr;
1809
35.6k
    int multi_ref = 0;
1810
35.6k
    int r1, r2, sn, nref, embed_ref, no_ref;
1811
35.6k
    bam_list *spares;
1812
1813
35.6k
    if (!c->bams)
1814
0
        goto err;
1815
1816
35.6k
    if (CRAM_MAJOR_VERS(fd->version) == 1)
1817
0
        goto err;
1818
1819
//#define goto_err {fprintf(stderr, "ERR at %s:%d\n", __FILE__, __LINE__);goto err;}
1820
35.6k
#define goto_err goto err
1821
1822
    // Don't try embed ref if we repeatedly fail
1823
35.6k
    pthread_mutex_lock(&fd->ref_lock);
1824
35.6k
    int failed_embed = (fd->no_ref_counter >= 5); // maximum 5 tries
1825
35.6k
    if (!failed_embed && c->embed_ref == -2 && c->ref_id >= 0) {
1826
465
        hts_log_warning("Retrying embed_ref=2 mode for #%d/5", fd->no_ref_counter);
1827
465
        fd->no_ref = c->no_ref = 0;
1828
465
        fd->embed_ref = c->embed_ref = 2;
1829
35.2k
    } else if (failed_embed && c->embed_ref == -2) {
1830
        // We've tried several times, so this time give up for good
1831
22
        hts_log_warning("Keeping non-ref mode from now on");
1832
22
        fd->embed_ref = c->embed_ref = 0;
1833
22
    }
1834
35.6k
    pthread_mutex_unlock(&fd->ref_lock);
1835
1836
36.7k
 restart:
1837
    /* Cache references up-front if we have unsorted access patterns */
1838
36.7k
    pthread_mutex_lock(&fd->ref_lock);
1839
36.7k
    nref = fd->refs->nref;
1840
36.7k
    pthread_mutex_unlock(&fd->ref_lock);
1841
36.7k
    embed_ref = c->embed_ref;
1842
36.7k
    no_ref = c->no_ref;
1843
1844
    /* To create M5 strings */
1845
    /* Fetch reference sequence */
1846
36.7k
    if (!no_ref) {
1847
35.1k
        if (!c->bams || !c->curr_c_rec || !c->nbams)
1848
169
            goto_err;
1849
35.0k
        bam_seq_t *b = &c->bams[0];
1850
1851
35.0k
        if (embed_ref <= 1) {
1852
4.45k
            char *ref = cram_get_ref(fd, bam_ref(b), 1, 0);
1853
4.45k
            if (!ref && bam_ref(b) >= 0) {
1854
9
                if (!c->pos_sorted) {
1855
                    // TODO: maybe also check fd->no_ref?
1856
0
                    hts_log_warning("Failed to load reference #%d",
1857
0
                                    bam_ref(b));
1858
0
                    hts_log_warning("Switching to non-ref mode");
1859
1860
0
                    pthread_mutex_lock(&fd->ref_lock);
1861
0
                    c->embed_ref = fd->embed_ref = 0;
1862
0
                    c->no_ref = fd->no_ref = 1;
1863
0
                    pthread_mutex_unlock(&fd->ref_lock);
1864
0
                    goto restart;
1865
0
                }
1866
1867
9
                if (c->multi_seq || embed_ref == 0) {
1868
0
                    hts_log_error("Failed to load reference #%d", bam_ref(b));
1869
0
                    return -1;
1870
0
                }
1871
9
                hts_log_warning("Failed to load reference #%d", bam_ref(b));
1872
9
                hts_log_warning("Enabling embed_ref=2 mode to auto-generate"
1873
9
                                " reference");
1874
9
                if (embed_ref <= 0)
1875
9
                    hts_log_warning("NOTE: the CRAM file will be bigger than"
1876
9
                                    " using an external reference");
1877
9
                pthread_mutex_lock(&fd->ref_lock);
1878
9
                embed_ref = c->embed_ref = fd->embed_ref = 2;
1879
9
                pthread_mutex_unlock(&fd->ref_lock);
1880
9
                goto auto_ref;
1881
4.44k
            } else if (ref) {
1882
0
                if (validate_md5(fd, c->ref_seq_id) < 0)
1883
0
                    goto_err;
1884
0
            }
1885
4.44k
            if ((c->ref_id = bam_ref(b)) >= 0) {
1886
0
                c->ref_seq_id = c->ref_id;
1887
0
                c->ref       = fd->refs->ref_id[c->ref_seq_id]->seq;
1888
0
                c->ref_start = 1;
1889
0
                c->ref_end   = fd->refs->ref_id[c->ref_seq_id]->length;
1890
0
            }
1891
30.5k
        } else {
1892
30.5k
        auto_ref:
1893
            // Auto-embed ref.
1894
            // This starts as 'N' and is amended on-the-fly as we go
1895
            // based on MD:Z tags.
1896
30.5k
            if ((c->ref_id = bam_ref(b)) >= 0) {
1897
15.8k
                c->ref = NULL;
1898
                // c->ref_free is boolean; whether to free c->ref.  In this
1899
                // case c->ref will be our auto-embedded sequence instead of
1900
                // a "global" portion of reference from fd->refs.
1901
                // Do not confuse with fd->ref_free which is a pointer to a
1902
                // reference string to free.
1903
15.8k
                c->ref_free = 1;
1904
15.8k
            } else {
1905
                // Double check for broken input.  We shouldn't have
1906
                // embedded references enabled for unmapped data, but our
1907
                // data could be broken.
1908
14.7k
                embed_ref = 0;
1909
14.7k
                no_ref = c->no_ref = 1;
1910
14.7k
            }
1911
30.5k
        }
1912
35.0k
        c->ref_seq_id = c->ref_id;
1913
35.0k
    } else {
1914
1.61k
        c->ref_id = bam_ref(&c->bams[0]);
1915
1.61k
        cram_ref_incr(fd->refs, c->ref_id);
1916
1.61k
        c->ref_seq_id = c->ref_id;
1917
1.61k
    }
1918
1919
36.6k
    if (!no_ref && c->refs_used) {
1920
434
        for (i = 0; i < nref; i++) {
1921
272
            if (c->refs_used[i]) {
1922
110
                if (cram_get_ref(fd, i, 1, 0)) {
1923
0
                    if (validate_md5(fd, i) < 0)
1924
0
                        goto_err;
1925
110
                } else {
1926
110
                    hts_log_warning("Failed to find reference, "
1927
110
                                    "switching to non-ref mode");
1928
110
                    no_ref = c->no_ref = 1;
1929
110
                }
1930
110
            }
1931
272
        }
1932
162
    }
1933
1934
    /* Turn bams into cram_records and gather basic stats */
1935
71.4k
    for (r1 = sn = 0; r1 < c->curr_c_rec; sn++) {
1936
36.6k
        cram_slice *s = c->slices[sn];
1937
36.6k
        int64_t first_base = INT64_MAX, last_base = INT64_MIN;
1938
1939
36.6k
        int r1_start = r1;
1940
1941
36.6k
        assert(sn < c->curr_slice);
1942
1943
        // Discover which read names *may* be safely removed.
1944
        // Ie which ones have all their records in this slice.
1945
36.6k
        if (lossy_read_names(fd, c, s, r1_start) != 0)
1946
0
            return -1;
1947
1948
        // Tracking of MD tags so we can spot when the auto-generated values
1949
        // will differ from the current stored ones.  The kstring here is
1950
        // simply to avoid excessive malloc and free calls.  All initialisation
1951
        // is done within process_one_read().
1952
36.6k
        kstring_t MD = {0};
1953
1954
        // Embed consensus / MD-generated ref
1955
36.6k
        if (embed_ref == 2) {
1956
15.8k
            if (c->ref_id < 0 || cram_generate_reference(c, s, r1) < 0) {
1957
                // Should this be a permanent thing via fd->no_ref?
1958
                // Doing so means we cannot easily switch back again should
1959
                // things fix themselves later on.  This is likely not a
1960
                // concern though as failure to generate a reference implies
1961
                // unsorted data which is rarely recovered from.
1962
1963
                // Only if sn == 0.  We're hosed if we're on the 2nd slice and
1964
                // the first worked, as no-ref is a container global param.
1965
1.09k
                if (sn > 0) {
1966
0
                    hts_log_error("Failed to build reference, "
1967
0
                                  "switching to non-ref mode");
1968
0
                    return -1;
1969
1.09k
                } else {
1970
1.09k
                    hts_log_warning("Failed to build reference, "
1971
1.09k
                                    "switching to non-ref mode");
1972
1.09k
                }
1973
1.09k
                pthread_mutex_lock(&fd->ref_lock);
1974
1.09k
                c->embed_ref = fd->embed_ref = -2; // was previously embed_ref
1975
1.09k
                c->no_ref = fd->no_ref = 1;
1976
1.09k
                fd->no_ref_counter++; // more likely to keep permanent action
1977
1.09k
                pthread_mutex_unlock(&fd->ref_lock);
1978
1.09k
                failed_embed = 1;
1979
1.09k
                goto restart;
1980
14.7k
            } else {
1981
14.7k
                pthread_mutex_lock(&fd->ref_lock);
1982
14.7k
                fd->no_ref_counter -= (fd->no_ref_counter > 0);
1983
14.7k
                pthread_mutex_unlock(&fd->ref_lock);
1984
14.7k
            }
1985
1986
14.7k
            hts_pos_t rlen = MAX(fd->refs->ref_id[c->ref_id]->LN_length,
1987
14.7k
                                 fd->refs->ref_id[c->ref_id]->length);
1988
14.7k
            if (c->ref_end > rlen && rlen)
1989
4.87k
                c->ref_end = rlen;
1990
14.7k
        }
1991
1992
        // Iterate through records creating the cram blocks for some
1993
        // fields and just gathering stats for others.
1994
9.45M
        for (r2 = 0; r1 < c->curr_c_rec && r2 < s->hdr->num_records; r1++, r2++) {
1995
9.41M
            cram_record *cr = &s->crecs[r2];
1996
9.41M
            bam_seq_t *b = &c->bams[r1];
1997
1998
            /* If multi-ref we need to cope with changing reference per seq */
1999
9.41M
            if (c->multi_seq && !no_ref) {
2000
340
                if (bam_ref(b) != c->ref_seq_id && bam_ref(b) >= 0) {
2001
0
                    if (c->ref_seq_id >= 0)
2002
0
                        cram_ref_decr(fd->refs, c->ref_seq_id);
2003
2004
0
                    if (!cram_get_ref(fd, bam_ref(b), 1, 0)) {
2005
0
                        hts_log_error("Failed to load reference #%d", bam_ref(b));
2006
0
                        free(MD.s);
2007
0
                        return -1;
2008
0
                    }
2009
0
                    if (validate_md5(fd, bam_ref(b)) < 0)
2010
0
                        return -1;
2011
2012
0
                    c->ref_seq_id = bam_ref(b); // overwritten later by -2
2013
0
                    if (!fd->refs->ref_id[c->ref_seq_id]->seq)
2014
0
                        return -1;
2015
0
                    c->ref       = fd->refs->ref_id[c->ref_seq_id]->seq;
2016
0
                    c->ref_start = 1;
2017
0
                    c->ref_end   = fd->refs->ref_id[c->ref_seq_id]->length;
2018
0
                }
2019
340
            }
2020
2021
9.41M
            if (process_one_read(fd, c, s, cr, b, r2, &MD, embed_ref,
2022
9.41M
                                 no_ref) != 0) {
2023
646
                free(MD.s);
2024
646
                return -1;
2025
646
            }
2026
2027
9.41M
            if (first_base > cr->apos)
2028
35.4k
                first_base = cr->apos;
2029
2030
9.41M
            if (last_base < cr->aend)
2031
35.2k
                last_base = cr->aend;
2032
9.41M
        }
2033
2034
34.8k
        free(MD.s);
2035
2036
        // Process_one_read doesn't add read names as it can change
2037
        // its mind during the loop on the CRAM_FLAG_DETACHED setting
2038
        // of earlier records (if it detects the auto-generation of
2039
        // TLEN is incorrect).  This affects which read-names can be
2040
        // lossily compressed, so we do these in another pass.
2041
34.8k
        if (add_read_names(fd, c, s, r1_start) < 0)
2042
0
            return -1;
2043
2044
34.8k
        if (c->multi_seq) {
2045
564
            s->hdr->ref_seq_id    = -2;
2046
564
            s->hdr->ref_seq_start = 0;
2047
564
            s->hdr->ref_seq_span  = 0;
2048
34.3k
        } else if (c->ref_id == -1 && CRAM_ge31(fd->version)) {
2049
            // Spec states span=0, but it broke our range queries.
2050
            // See commit message for this and prior.
2051
18.8k
            s->hdr->ref_seq_id    = -1;
2052
18.8k
            s->hdr->ref_seq_start = 0;
2053
18.8k
            s->hdr->ref_seq_span  = 0;
2054
18.8k
        } else {
2055
15.4k
            s->hdr->ref_seq_id    = c->ref_id;
2056
15.4k
            s->hdr->ref_seq_start = first_base;
2057
15.4k
            s->hdr->ref_seq_span  = MAX(0, last_base - first_base + 1);
2058
15.4k
        }
2059
34.8k
        s->hdr->num_records = r2;
2060
2061
        // Processed a slice, now stash the aux blocks so the next
2062
        // slice can start aggregating them from the start again.
2063
34.8k
        if (c->tags_used->n_occupied) {
2064
30.5k
            int ntags = c->tags_used->n_occupied;
2065
30.5k
            s->aux_block = hts_calloc(hts_prod_sat2(ntags, 2), sizeof(*s->aux_block));
2066
30.5k
            if (!s->aux_block)
2067
0
                return -1;
2068
2069
30.5k
            khint_t k;
2070
2071
30.5k
            s->naux_block = 0;
2072
166k
            for (k = kh_begin(c->tags_used); k != kh_end(c->tags_used); k++) {
2073
135k
                if (!kh_exist(c->tags_used, k))
2074
75.5k
                    continue;
2075
2076
59.9k
                cram_tag_map *tm = kh_val(c->tags_used, k);
2077
59.9k
                if (!tm) goto_err;
2078
59.9k
                if (!tm->blk) continue;
2079
59.9k
                s->aux_block[s->naux_block++] = tm->blk;
2080
59.9k
                tm->blk = NULL;
2081
59.9k
                if (!tm->blk2) continue;
2082
0
                s->aux_block[s->naux_block++] = tm->blk2;
2083
0
                tm->blk2 = NULL;
2084
0
            }
2085
30.5k
            assert(s->naux_block <= 2*c->tags_used->n_occupied);
2086
30.5k
        }
2087
34.8k
    }
2088
2089
34.8k
    if (c->multi_seq && !no_ref) {
2090
52
        if (c->ref_seq_id >= 0)
2091
0
            cram_ref_decr(fd->refs, c->ref_seq_id);
2092
52
    }
2093
2094
    /* Link our bams[] array onto the spare bam list for reuse */
2095
34.8k
    spares = malloc(sizeof(*spares));
2096
34.8k
    if (!spares) goto_err;
2097
34.8k
    spares->bams = c->bams;
2098
34.8k
    spares->nbams = c->nbams;
2099
34.8k
    pthread_mutex_lock(&fd->bam_list_lock);
2100
34.8k
    spares->next = fd->bl;
2101
34.8k
    fd->bl = spares;
2102
34.8k
    pthread_mutex_unlock(&fd->bam_list_lock);
2103
34.8k
    c->bams = NULL;
2104
2105
    /* Detect if a multi-seq container */
2106
34.8k
    cram_stats_encoding(fd, c->stats[DS_RI]);
2107
34.8k
    multi_ref = c->stats[DS_RI]->nvals > 1;
2108
34.8k
    pthread_mutex_lock(&fd->metrics_lock);
2109
34.8k
    fd->last_RI_count = c->stats[DS_RI]->nvals;
2110
34.8k
    pthread_mutex_unlock(&fd->metrics_lock);
2111
2112
2113
34.8k
    if (multi_ref) {
2114
235
        hts_log_info("Multi-ref container");
2115
235
        c->ref_seq_id = -2;
2116
235
        c->ref_seq_start = 0;
2117
235
        c->ref_seq_span = 0;
2118
235
    }
2119
2120
2121
    /* Compute MD5s */
2122
34.8k
    no_ref = c->no_ref;
2123
69.7k
    for (i = 0; i < c->curr_slice; i++) {
2124
34.8k
        cram_slice *s = c->slices[i];
2125
2126
34.8k
        if (CRAM_MAJOR_VERS(fd->version) != 1) {
2127
34.8k
            if (s->hdr->ref_seq_id >= 0 && c->multi_seq == 0 && !no_ref) {
2128
14.6k
                hts_md5_context *md5 = hts_md5_init();
2129
14.6k
                if (!md5)
2130
0
                    return -1;
2131
14.6k
                hts_md5_update(md5,
2132
14.6k
                               c->ref + s->hdr->ref_seq_start - c->ref_start,
2133
14.6k
                               s->hdr->ref_seq_span);
2134
14.6k
                hts_md5_final(s->hdr->md5, md5);
2135
14.6k
                hts_md5_destroy(md5);
2136
20.2k
            } else {
2137
20.2k
                memset(s->hdr->md5, 0, 16);
2138
20.2k
            }
2139
34.8k
        }
2140
34.8k
    }
2141
2142
34.8k
    c->num_records = 0;
2143
34.8k
    c->num_blocks = 1; // cram_block_compression_hdr
2144
34.8k
    c->length = 0;
2145
2146
    //fprintf(stderr, "=== BF ===\n");
2147
34.8k
    h->codecs[DS_BF] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_BF]),
2148
34.8k
                                         c->stats[DS_BF], E_INT, NULL,
2149
34.8k
                                         fd->version, &fd->vv);
2150
34.8k
    if (c->stats[DS_BF]->nvals && !h->codecs[DS_BF]) goto_err;
2151
2152
    //fprintf(stderr, "=== CF ===\n");
2153
34.8k
    h->codecs[DS_CF] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_CF]),
2154
34.8k
                                         c->stats[DS_CF], E_INT, NULL,
2155
34.8k
                                         fd->version, &fd->vv);
2156
34.8k
    if (c->stats[DS_CF]->nvals && !h->codecs[DS_CF]) goto_err;
2157
2158
    //fprintf(stderr, "=== RN ===\n");
2159
    //h->codecs[DS_RN] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_RN]),
2160
    //                                     c->stats[DS_RN], E_BYTE_ARRAY, NULL,
2161
    //                                     fd->version);
2162
2163
    //fprintf(stderr, "=== AP ===\n");
2164
34.8k
    if (c->pos_sorted) {
2165
33.9k
        if (c->pos_sorted)
2166
33.9k
            h->codecs[DS_AP] =
2167
33.9k
                cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_AP]),
2168
33.9k
                                  c->stats[DS_AP], E_INT,
2169
33.9k
                                  NULL, fd->version, &fd->vv);
2170
0
        else
2171
            // Unsorted data has no stats, but hard-code VARINT_SIGNED / EXT.
2172
0
            h->codecs[DS_AP] = cram_encoder_init(E_EXTERNAL, NULL,
2173
0
                                                 E_INT, NULL,
2174
0
                                                 fd->version, &fd->vv);
2175
33.9k
    } else {
2176
        // Should we consider dropping use for CRAM 3.0 onwards?
2177
978
        hts_pos_t p[2] = {0, c->max_apos};
2178
978
        h->codecs[DS_AP] = cram_encoder_init(E_BETA, NULL, E_INT,
2179
978
                                             p, fd->version, &fd->vv);
2180
978
    }
2181
34.8k
    if (!h->codecs[DS_AP]) goto_err;
2182
2183
    //fprintf(stderr, "=== RG ===\n");
2184
34.7k
    h->codecs[DS_RG] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_RG]),
2185
34.7k
                                         c->stats[DS_RG],
2186
34.7k
                                         E_INT,
2187
34.7k
                                         NULL,
2188
34.7k
                                         fd->version, &fd->vv);
2189
34.7k
    if (c->stats[DS_RG]->nvals && !h->codecs[DS_RG]) goto_err;
2190
2191
    //fprintf(stderr, "=== MQ ===\n");
2192
34.7k
    h->codecs[DS_MQ] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_MQ]),
2193
34.7k
                                         c->stats[DS_MQ], E_INT, NULL,
2194
34.7k
                                         fd->version, &fd->vv);
2195
34.7k
    if (c->stats[DS_MQ]->nvals && !h->codecs[DS_MQ]) goto_err;
2196
2197
    //fprintf(stderr, "=== NS ===\n");
2198
34.7k
    h->codecs[DS_NS] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_NS]),
2199
34.7k
                                         c->stats[DS_NS], E_INT, NULL,
2200
34.7k
                                         fd->version, &fd->vv);
2201
34.7k
    if (c->stats[DS_NS]->nvals && !h->codecs[DS_NS]) goto_err;
2202
2203
    //fprintf(stderr, "=== MF ===\n");
2204
34.7k
    h->codecs[DS_MF] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_MF]),
2205
34.7k
                                         c->stats[DS_MF], E_INT, NULL,
2206
34.7k
                                         fd->version, &fd->vv);
2207
34.7k
    if (c->stats[DS_MF]->nvals && !h->codecs[DS_MF]) goto_err;
2208
2209
    //fprintf(stderr, "=== TS ===\n");
2210
34.7k
    h->codecs[DS_TS] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_TS]),
2211
34.7k
                                         c->stats[DS_TS], E_INT, NULL,
2212
34.7k
                                         fd->version, &fd->vv);
2213
34.7k
    if (c->stats[DS_TS]->nvals && !h->codecs[DS_TS]) goto_err;
2214
2215
    //fprintf(stderr, "=== NP ===\n");
2216
34.7k
    h->codecs[DS_NP] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_NP]),
2217
34.7k
                                         c->stats[DS_NP], E_INT, NULL,
2218
34.7k
                                         fd->version, &fd->vv);
2219
34.7k
    if (c->stats[DS_NP]->nvals && !h->codecs[DS_NP]) goto_err;
2220
2221
    //fprintf(stderr, "=== NF ===\n");
2222
34.7k
    h->codecs[DS_NF] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_NF]),
2223
34.7k
                                         c->stats[DS_NF], E_INT, NULL,
2224
34.7k
                                         fd->version, &fd->vv);
2225
34.7k
    if (c->stats[DS_NF]->nvals && !h->codecs[DS_NF]) goto_err;
2226
2227
    //fprintf(stderr, "=== RL ===\n");
2228
34.7k
    h->codecs[DS_RL] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_RL]),
2229
34.7k
                                         c->stats[DS_RL], E_INT, NULL,
2230
34.7k
                                         fd->version, &fd->vv);
2231
34.7k
    if (c->stats[DS_RL]->nvals && !h->codecs[DS_RL]) goto_err;
2232
2233
    //fprintf(stderr, "=== FN ===\n");
2234
34.7k
    h->codecs[DS_FN] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_FN]),
2235
34.7k
                                         c->stats[DS_FN], E_INT, NULL,
2236
34.7k
                                         fd->version, &fd->vv);
2237
34.7k
    if (c->stats[DS_FN]->nvals && !h->codecs[DS_FN]) goto_err;
2238
2239
    //fprintf(stderr, "=== FC ===\n");
2240
34.7k
    h->codecs[DS_FC] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_FC]),
2241
34.7k
                                         c->stats[DS_FC], E_BYTE, NULL,
2242
34.7k
                                         fd->version, &fd->vv);
2243
34.7k
    if (c->stats[DS_FC]->nvals && !h->codecs[DS_FC]) goto_err;
2244
2245
    //fprintf(stderr, "=== FP ===\n");
2246
34.7k
    h->codecs[DS_FP] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_FP]),
2247
34.7k
                                         c->stats[DS_FP], E_INT, NULL,
2248
34.7k
                                         fd->version, &fd->vv);
2249
34.7k
    if (c->stats[DS_FP]->nvals && !h->codecs[DS_FP]) goto_err;
2250
2251
    //fprintf(stderr, "=== DL ===\n");
2252
34.7k
    h->codecs[DS_DL] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_DL]),
2253
34.7k
                                         c->stats[DS_DL], E_INT, NULL,
2254
34.7k
                                         fd->version, &fd->vv);
2255
34.7k
    if (c->stats[DS_DL]->nvals && !h->codecs[DS_DL]) goto_err;
2256
2257
    //fprintf(stderr, "=== BA ===\n");
2258
34.7k
    h->codecs[DS_BA] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_BA]),
2259
34.7k
                                         c->stats[DS_BA], E_BYTE, NULL,
2260
34.7k
                                         fd->version, &fd->vv);
2261
34.7k
    if (c->stats[DS_BA]->nvals && !h->codecs[DS_BA]) goto_err;
2262
2263
34.7k
    if (CRAM_MAJOR_VERS(fd->version) >= 3) {
2264
34.7k
        cram_byte_array_len_encoder e;
2265
2266
34.7k
        e.len_encoding = E_EXTERNAL;
2267
34.7k
        e.len_dat = (void *)DS_BB_len;
2268
        //e.len_dat = (void *)DS_BB;
2269
2270
34.7k
        e.val_encoding = E_EXTERNAL;
2271
34.7k
        e.val_dat = (void *)DS_BB;
2272
2273
34.7k
        h->codecs[DS_BB] = cram_encoder_init(E_BYTE_ARRAY_LEN, NULL,
2274
34.7k
                                             E_BYTE_ARRAY, (void *)&e,
2275
34.7k
                                             fd->version, &fd->vv);
2276
34.7k
        if (!h->codecs[DS_BB]) goto_err;
2277
34.7k
    } else {
2278
0
        h->codecs[DS_BB] = NULL;
2279
0
    }
2280
2281
    //fprintf(stderr, "=== BS ===\n");
2282
34.7k
    h->codecs[DS_BS] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_BS]),
2283
34.7k
                                         c->stats[DS_BS], E_BYTE, NULL,
2284
34.7k
                                         fd->version, &fd->vv);
2285
34.7k
    if (c->stats[DS_BS]->nvals && !h->codecs[DS_BS]) goto_err;
2286
2287
34.7k
    if (CRAM_MAJOR_VERS(fd->version) == 1) {
2288
0
        h->codecs[DS_TL] = NULL;
2289
0
        h->codecs[DS_RI] = NULL;
2290
0
        h->codecs[DS_RS] = NULL;
2291
0
        h->codecs[DS_PD] = NULL;
2292
0
        h->codecs[DS_HC] = NULL;
2293
0
        h->codecs[DS_SC] = NULL;
2294
2295
        //fprintf(stderr, "=== TC ===\n");
2296
0
        h->codecs[DS_TC] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_TC]),
2297
0
                                             c->stats[DS_TC], E_BYTE, NULL,
2298
0
                                             fd->version, &fd->vv);
2299
0
        if (c->stats[DS_TC]->nvals && !h->codecs[DS_TC]) goto_err;
2300
2301
        //fprintf(stderr, "=== TN ===\n");
2302
0
        h->codecs[DS_TN] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_TN]),
2303
0
                                             c->stats[DS_TN], E_INT, NULL,
2304
0
                                             fd->version, &fd->vv);
2305
0
        if (c->stats[DS_TN]->nvals && !h->codecs[DS_TN]) goto_err;
2306
34.7k
    } else {
2307
34.7k
        h->codecs[DS_TC] = NULL;
2308
34.7k
        h->codecs[DS_TN] = NULL;
2309
2310
        //fprintf(stderr, "=== TL ===\n");
2311
34.7k
        h->codecs[DS_TL] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_TL]),
2312
34.7k
                                             c->stats[DS_TL], E_INT, NULL,
2313
34.7k
                                             fd->version, &fd->vv);
2314
34.7k
        if (c->stats[DS_TL]->nvals && !h->codecs[DS_TL]) goto_err;
2315
2316
2317
        //fprintf(stderr, "=== RI ===\n");
2318
34.7k
        h->codecs[DS_RI] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_RI]),
2319
34.7k
                                             c->stats[DS_RI], E_INT, NULL,
2320
34.7k
                                             fd->version, &fd->vv);
2321
34.7k
        if (c->stats[DS_RI]->nvals && !h->codecs[DS_RI]) goto_err;
2322
2323
        //fprintf(stderr, "=== RS ===\n");
2324
34.7k
        h->codecs[DS_RS] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_RS]),
2325
34.7k
                                             c->stats[DS_RS], E_INT, NULL,
2326
34.7k
                                             fd->version, &fd->vv);
2327
34.7k
        if (c->stats[DS_RS]->nvals && !h->codecs[DS_RS]) goto_err;
2328
2329
        //fprintf(stderr, "=== PD ===\n");
2330
34.7k
        h->codecs[DS_PD] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_PD]),
2331
34.7k
                                             c->stats[DS_PD], E_INT, NULL,
2332
34.7k
                                             fd->version, &fd->vv);
2333
34.7k
        if (c->stats[DS_PD]->nvals && !h->codecs[DS_PD]) goto_err;
2334
2335
        //fprintf(stderr, "=== HC ===\n");
2336
34.7k
        h->codecs[DS_HC] = cram_encoder_init(cram_stats_encoding(fd, c->stats[DS_HC]),
2337
34.7k
                                             c->stats[DS_HC], E_INT, NULL,
2338
34.7k
                                             fd->version, &fd->vv);
2339
34.7k
        if (c->stats[DS_HC]->nvals && !h->codecs[DS_HC]) goto_err;
2340
2341
        //fprintf(stderr, "=== SC ===\n");
2342
34.7k
        if (1) {
2343
34.7k
            int i2[2] = {0, DS_SC};
2344
2345
34.7k
            h->codecs[DS_SC] = cram_encoder_init(E_BYTE_ARRAY_STOP, NULL,
2346
34.7k
                                                 E_BYTE_ARRAY, (void *)i2,
2347
34.7k
                                                 fd->version, &fd->vv);
2348
34.7k
        } else {
2349
            // Appears to be no practical benefit to using this method,
2350
            // but it may work better if we start mixing SC, IN and BB
2351
            // elements into the same external block.
2352
0
            cram_byte_array_len_encoder e;
2353
2354
0
            e.len_encoding = E_EXTERNAL;
2355
0
            e.len_dat = (void *)DS_SC_len;
2356
2357
0
            e.val_encoding = E_EXTERNAL;
2358
0
            e.val_dat = (void *)DS_SC;
2359
2360
0
            h->codecs[DS_SC] = cram_encoder_init(E_BYTE_ARRAY_LEN, NULL,
2361
0
                                                 E_BYTE_ARRAY, (void *)&e,
2362
0
                                                 fd->version, &fd->vv);
2363
0
        }
2364
34.7k
        if (!h->codecs[DS_SC]) goto_err;
2365
34.7k
    }
2366
2367
    //fprintf(stderr, "=== IN ===\n");
2368
34.7k
    {
2369
34.7k
        int i2[2] = {0, DS_IN};
2370
34.7k
        h->codecs[DS_IN] = cram_encoder_init(E_BYTE_ARRAY_STOP, NULL,
2371
34.7k
                                             E_BYTE_ARRAY, (void *)i2,
2372
34.7k
                                             fd->version, &fd->vv);
2373
34.7k
        if (!h->codecs[DS_IN]) goto_err;
2374
34.7k
    }
2375
2376
34.7k
    h->codecs[DS_QS] = cram_encoder_init(E_EXTERNAL, NULL, E_BYTE,
2377
34.7k
                                         (void *)DS_QS,
2378
34.7k
                                         fd->version, &fd->vv);
2379
34.7k
    if (!h->codecs[DS_QS]) goto_err;
2380
34.7k
    {
2381
34.7k
        int i2[2] = {0, DS_RN};
2382
34.7k
        h->codecs[DS_RN] = cram_encoder_init(E_BYTE_ARRAY_STOP, NULL,
2383
34.7k
                                             E_BYTE_ARRAY, (void *)i2,
2384
34.7k
                                             fd->version, &fd->vv);
2385
34.7k
        if (!h->codecs[DS_RN]) goto_err;
2386
34.7k
    }
2387
2388
2389
    /* Encode slices */
2390
69.3k
    for (i = 0; i < c->curr_slice; i++) {
2391
34.7k
        hts_log_info("Encode slice %d", i);
2392
2393
34.7k
        int local_embed_ref =
2394
34.7k
            embed_ref>0 && c->slices[i]->hdr->ref_seq_id != -1 ? 1 : 0;
2395
34.7k
        if (cram_encode_slice(fd, c, h, c->slices[i], local_embed_ref) != 0)
2396
187
            return -1;
2397
34.7k
    }
2398
2399
    /* Create compression header */
2400
34.5k
    {
2401
34.5k
        h->ref_seq_id    = c->ref_seq_id;
2402
34.5k
        h->ref_seq_start = c->ref_seq_start;
2403
34.5k
        h->ref_seq_span  = c->ref_seq_span;
2404
34.5k
        h->num_records   = c->num_records;
2405
34.5k
        h->qs_seq_orient = c->qs_seq_orient;
2406
        // slight misnomer - sorted or treat as-if sorted (ap_delta force to 1)
2407
34.5k
        h->AP_delta      = c->pos_sorted;
2408
34.5k
        memcpy(h->substitution_matrix, CRAM_SUBST_MATRIX, 20);
2409
2410
34.5k
        if (!(c_hdr = cram_encode_compression_header(fd, c, h, embed_ref)))
2411
0
            return -1;
2412
34.5k
    }
2413
2414
    /* Compute landmarks */
2415
    /* Fill out slice landmarks */
2416
34.5k
    c->num_landmarks = c->curr_slice;
2417
34.5k
    c->landmark = hts_malloc_p(sizeof(*c->landmark), c->num_landmarks);
2418
34.5k
    if (!c->landmark)
2419
0
        return -1;
2420
2421
    /*
2422
     * Slice offset starts after the first block, so we need to simulate
2423
     * writing it to work out the correct offset
2424
     */
2425
34.5k
    {
2426
34.5k
        slice_offset = c_hdr->method == RAW
2427
34.5k
            ? c_hdr->uncomp_size
2428
34.5k
            : c_hdr->comp_size;
2429
34.5k
        slice_offset += 2 + 4*(CRAM_MAJOR_VERS(fd->version) >= 3) +
2430
34.5k
            fd->vv.varint_size(c_hdr->content_id) +
2431
34.5k
            fd->vv.varint_size(c_hdr->comp_size) +
2432
34.5k
            fd->vv.varint_size(c_hdr->uncomp_size);
2433
34.5k
    }
2434
2435
34.5k
    c->ref_seq_id    = c->slices[0]->hdr->ref_seq_id;
2436
34.5k
    if (c->ref_seq_id == -1 && CRAM_ge31(fd->version)) {
2437
        // Spec states span=0, but it broke our range queries.
2438
        // See commit message for this and prior.
2439
18.7k
        c->ref_seq_start = 0;
2440
18.7k
        c->ref_seq_span  = 0;
2441
18.7k
    } else {
2442
15.8k
        c->ref_seq_start = c->slices[0]->hdr->ref_seq_start;
2443
15.8k
        c->ref_seq_span  = c->slices[0]->hdr->ref_seq_span;
2444
15.8k
    }
2445
69.1k
    for (i = 0; i < c->curr_slice; i++) {
2446
34.5k
        cram_slice *s = c->slices[i];
2447
2448
34.5k
        c->num_blocks += s->hdr->num_blocks + 1; // slice header
2449
34.5k
        c->landmark[i] = slice_offset;
2450
2451
34.5k
        if (s->hdr->ref_seq_start + s->hdr->ref_seq_span >
2452
34.5k
            c->ref_seq_start + c->ref_seq_span) {
2453
0
            c->ref_seq_span = s->hdr->ref_seq_start + s->hdr->ref_seq_span
2454
0
                - c->ref_seq_start;
2455
0
        }
2456
2457
34.5k
        slice_offset += s->hdr_block->method == RAW
2458
34.5k
            ? s->hdr_block->uncomp_size
2459
34.5k
            : s->hdr_block->comp_size;
2460
2461
34.5k
        slice_offset += 2 + 4*(CRAM_MAJOR_VERS(fd->version) >= 3) +
2462
34.5k
            fd->vv.varint_size(s->hdr_block->content_id) +
2463
34.5k
            fd->vv.varint_size(s->hdr_block->comp_size) +
2464
34.5k
            fd->vv.varint_size(s->hdr_block->uncomp_size);
2465
2466
237k
        for (j = 0; j < s->hdr->num_blocks; j++) {
2467
203k
            slice_offset += 2 + 4*(CRAM_MAJOR_VERS(fd->version) >= 3) +
2468
203k
                fd->vv.varint_size(s->block[j]->content_id) +
2469
203k
                fd->vv.varint_size(s->block[j]->comp_size) +
2470
203k
                fd->vv.varint_size(s->block[j]->uncomp_size);
2471
2472
203k
            slice_offset += s->block[j]->method == RAW
2473
203k
                ? s->block[j]->uncomp_size
2474
203k
                : s->block[j]->comp_size;
2475
203k
        }
2476
34.5k
    }
2477
34.5k
    c->length += slice_offset; // just past the final slice
2478
2479
34.5k
    c->comp_hdr_block = c_hdr;
2480
2481
34.5k
    if (c->ref_seq_id >= 0) {
2482
15.2k
        if (c->ref_free) {
2483
15.1k
            free(c->ref);
2484
15.1k
            c->ref = NULL;
2485
15.1k
        } else {
2486
74
            cram_ref_decr(fd->refs, c->ref_seq_id);
2487
74
        }
2488
15.2k
    }
2489
2490
    /* Cache references up-front if we have unsorted access patterns */
2491
34.5k
    if (!no_ref && c->refs_used) {
2492
213
        for (i = 0; i < fd->refs->nref; i++) {
2493
161
            if (c->refs_used[i])
2494
0
                cram_ref_decr(fd->refs, i);
2495
161
        }
2496
52
    }
2497
2498
34.5k
    return 0;
2499
2500
272
 err:
2501
272
    return -1;
2502
34.5k
}
2503
2504
2505
/*
2506
 * Adds a feature code to a read within a slice. For purposes of minimising
2507
 * memory allocations and fragmentation we have one array of features for all
2508
 * reads within the slice. We return the index into this array for this new
2509
 * feature.
2510
 *
2511
 * Returns feature index on success
2512
 *         -1 on failure.
2513
 */
2514
static int cram_add_feature(cram_container *c, cram_slice *s,
2515
160k
                            cram_record *r, cram_feature *f) {
2516
160k
    if (s->nfeatures >= s->afeatures) {
2517
15.2k
        s->afeatures = s->afeatures ? s->afeatures*2 : 1024;
2518
15.2k
        cram_feature *features
2519
15.2k
            = hts_realloc_p(s->features, sizeof(*s->features), s->afeatures);
2520
15.2k
        if (!features)
2521
0
            return -1;
2522
15.2k
        s->features = features;
2523
15.2k
    }
2524
2525
160k
    if (!r->nfeature++) {
2526
48.0k
        r->feature = s->nfeatures;
2527
48.0k
        if (cram_stats_add(c->stats[DS_FP], f->X.pos) < 0)
2528
0
            return -1;
2529
112k
    } else {
2530
112k
        if (cram_stats_add(c->stats[DS_FP],
2531
112k
                           f->X.pos - s->features[r->feature + r->nfeature-2].X.pos) < 0)
2532
0
            return -1;
2533
2534
112k
    }
2535
160k
    if (cram_stats_add(c->stats[DS_FC], f->X.code) < 0)
2536
0
        return -1;
2537
2538
160k
    s->features[s->nfeatures++] = *f;
2539
2540
160k
    return 0;
2541
160k
}
2542
2543
static int cram_add_substitution(cram_fd *fd, cram_container *c,
2544
                                 cram_slice *s, cram_record *r,
2545
27.3k
                                 int pos, char base, char qual, char ref) {
2546
27.3k
    cram_feature f;
2547
2548
    // seq=ACGTN vs ref=ACGT or seq=ACGT vs ref=ACGTN
2549
27.3k
    if (fd->L2[(uc)base]<4 || (fd->L2[(uc)base]<5 && fd->L2[(uc)ref]<4)) {
2550
5.97k
        f.X.pos = pos+1;
2551
5.97k
        f.X.code = 'X';
2552
5.97k
        f.X.base = fd->cram_sub_matrix[ref&0x1f][base&0x1f];
2553
5.97k
        if (cram_stats_add(c->stats[DS_BS], f.X.base) < 0)
2554
0
            return -1;
2555
21.3k
    } else {
2556
21.3k
        f.B.pos = pos+1;
2557
21.3k
        f.B.code = 'B';
2558
21.3k
        f.B.base = base;
2559
21.3k
        f.B.qual = qual;
2560
21.3k
        if (cram_stats_add(c->stats[DS_BA], f.B.base) < 0) return -1;
2561
21.3k
        if (cram_stats_add(c->stats[DS_QS], f.B.qual) < 0) return -1;
2562
21.3k
        BLOCK_APPEND_CHAR(s->qual_blk, qual);
2563
21.3k
    }
2564
27.3k
    return cram_add_feature(c, s, r, &f);
2565
2566
0
 block_err:
2567
0
    return -1;
2568
27.3k
}
2569
2570
static int cram_add_bases(cram_fd *fd, cram_container *c,
2571
                          cram_slice *s, cram_record *r,
2572
2.32k
                          int pos, int len, char *base) {
2573
2.32k
    cram_feature f;
2574
2575
2.32k
    f.b.pos = pos+1;
2576
2.32k
    f.b.code = 'b';
2577
2.32k
    f.b.seq_idx = base - (char *)BLOCK_DATA(s->seqs_blk);
2578
2.32k
    f.b.len = len;
2579
2580
2.32k
    return cram_add_feature(c, s, r, &f);
2581
2.32k
}
2582
2583
static int cram_add_base(cram_fd *fd, cram_container *c,
2584
                         cram_slice *s, cram_record *r,
2585
34.4k
                         int pos, char base, char qual) {
2586
34.4k
    cram_feature f;
2587
34.4k
    f.B.pos = pos+1;
2588
34.4k
    f.B.code = 'B';
2589
34.4k
    f.B.base = base;
2590
34.4k
    f.B.qual = qual;
2591
34.4k
    if (cram_stats_add(c->stats[DS_BA], base) < 0) return -1;
2592
34.4k
    if (cram_stats_add(c->stats[DS_QS], qual) < 0) return -1;
2593
34.4k
    BLOCK_APPEND_CHAR(s->qual_blk, qual);
2594
34.4k
    return cram_add_feature(c, s, r, &f);
2595
2596
0
 block_err:
2597
0
    return -1;
2598
34.4k
}
2599
2600
static int cram_add_quality(cram_fd *fd, cram_container *c,
2601
                            cram_slice *s, cram_record *r,
2602
68
                            int pos, char qual) {
2603
68
    cram_feature f;
2604
68
    f.Q.pos = pos+1;
2605
68
    f.Q.code = 'Q';
2606
68
    f.Q.qual = qual;
2607
68
    if (cram_stats_add(c->stats[DS_QS], qual) < 0) return -1;
2608
68
    BLOCK_APPEND_CHAR(s->qual_blk, qual);
2609
68
    return cram_add_feature(c, s, r, &f);
2610
2611
0
 block_err:
2612
0
    return -1;
2613
68
}
2614
2615
static int cram_add_deletion(cram_container *c, cram_slice *s, cram_record *r,
2616
42.3k
                             int pos, int len, char *base) {
2617
42.3k
    cram_feature f;
2618
42.3k
    f.D.pos = pos+1;
2619
42.3k
    f.D.code = 'D';
2620
42.3k
    f.D.len = len;
2621
42.3k
    if (cram_stats_add(c->stats[DS_DL], len) < 0) return -1;
2622
42.3k
    return cram_add_feature(c, s, r, &f);
2623
42.3k
}
2624
2625
static int cram_add_softclip(cram_container *c, cram_slice *s, cram_record *r,
2626
19.5k
                             int pos, int len, char *base, int version) {
2627
19.5k
    cram_feature f;
2628
19.5k
    f.S.pos = pos+1;
2629
19.5k
    f.S.code = 'S';
2630
19.5k
    f.S.len = len;
2631
19.5k
    switch (CRAM_MAJOR_VERS(version)) {
2632
0
    case 1:
2633
0
        f.S.seq_idx = BLOCK_SIZE(s->base_blk);
2634
0
        BLOCK_APPEND(s->base_blk, base, len);
2635
0
        BLOCK_APPEND_CHAR(s->base_blk, '\0');
2636
0
        break;
2637
2638
0
    case 2:
2639
19.5k
    default:
2640
19.5k
        f.S.seq_idx = BLOCK_SIZE(s->soft_blk);
2641
19.5k
        if (base) {
2642
7.25k
            BLOCK_APPEND(s->soft_blk, base, len);
2643
12.2k
        } else {
2644
12.2k
            int i;
2645
140k
            for (i = 0; i < len; i++)
2646
128k
                BLOCK_APPEND_CHAR(s->soft_blk, 'N');
2647
12.2k
        }
2648
19.5k
        BLOCK_APPEND_CHAR(s->soft_blk, '\0');
2649
19.5k
        break;
2650
2651
        //default:
2652
        //    // v3.0 onwards uses BB data-series
2653
        //    f.S.seq_idx = BLOCK_SIZE(s->soft_blk);
2654
19.5k
    }
2655
19.5k
    return cram_add_feature(c, s, r, &f);
2656
2657
0
 block_err:
2658
0
    return -1;
2659
19.5k
}
2660
2661
static int cram_add_hardclip(cram_container *c, cram_slice *s, cram_record *r,
2662
31.9k
                             int pos, int len, char *base) {
2663
31.9k
    cram_feature f;
2664
31.9k
    f.S.pos = pos+1;
2665
31.9k
    f.S.code = 'H';
2666
31.9k
    f.S.len = len;
2667
31.9k
    if (cram_stats_add(c->stats[DS_HC], len) < 0) return -1;
2668
31.9k
    return cram_add_feature(c, s, r, &f);
2669
31.9k
}
2670
2671
static int cram_add_skip(cram_container *c, cram_slice *s, cram_record *r,
2672
964
                         int pos, int len, char *base) {
2673
964
    cram_feature f;
2674
964
    f.S.pos = pos+1;
2675
964
    f.S.code = 'N';
2676
964
    f.S.len = len;
2677
964
    if (cram_stats_add(c->stats[DS_RS], len) < 0) return -1;
2678
964
    return cram_add_feature(c, s, r, &f);
2679
964
}
2680
2681
static int cram_add_pad(cram_container *c, cram_slice *s, cram_record *r,
2682
904
                        int pos, int len, char *base) {
2683
904
    cram_feature f;
2684
904
    f.S.pos = pos+1;
2685
904
    f.S.code = 'P';
2686
904
    f.S.len = len;
2687
904
    if (cram_stats_add(c->stats[DS_PD], len) < 0) return -1;
2688
904
    return cram_add_feature(c, s, r, &f);
2689
904
}
2690
2691
static int cram_add_insertion(cram_container *c, cram_slice *s, cram_record *r,
2692
499
                              int pos, int len, char *base) {
2693
499
    cram_feature f;
2694
499
    f.I.pos = pos+1;
2695
499
    if (len == 1) {
2696
31
        char b = base ? *base : 'N';
2697
31
        f.i.code = 'i';
2698
31
        f.i.base = b;
2699
31
        if (cram_stats_add(c->stats[DS_BA], b) < 0) return -1;
2700
468
    } else {
2701
468
        f.I.code = 'I';
2702
468
        f.I.len = len;
2703
468
        f.S.seq_idx = BLOCK_SIZE(s->base_blk);
2704
468
        if (base) {
2705
327
            BLOCK_APPEND(s->base_blk, base, len);
2706
327
        } else {
2707
141
            int i;
2708
359k
            for (i = 0; i < len; i++)
2709
359k
                BLOCK_APPEND_CHAR(s->base_blk, 'N');
2710
141
        }
2711
468
        BLOCK_APPEND_CHAR(s->base_blk, '\0');
2712
468
    }
2713
499
    return cram_add_feature(c, s, r, &f);
2714
2715
0
 block_err:
2716
0
    return -1;
2717
499
}
2718
2719
/*
2720
 * Encodes auxiliary data. Largely duplicated from above, but done so to
2721
 * keep it simple and avoid a myriad of version ifs.
2722
 *
2723
 * Returns the RG header line pointed to by the BAM aux fields on success,
2724
 *         NULL on failure or no rg present, also sets "*err" to non-zero
2725
 */
2726
static sam_hrec_rg_t *cram_encode_aux(cram_fd *fd, bam_seq_t *b,
2727
                                      cram_container *c,
2728
                                      cram_slice *s, cram_record *cr,
2729
                                      int verbatim_NM, int verbatim_MD,
2730
                                      int NM, kstring_t *MD, int cf_tag,
2731
9.41M
                                      int no_ref, int *err) {
2732
9.41M
    char *aux, *orig;
2733
9.41M
    sam_hrec_rg_t *brg = NULL;
2734
9.41M
    int aux_size = bam_get_l_aux(b);
2735
9.41M
    const char *aux_end = bam_data_end(b);
2736
9.41M
    cram_block *td_b = c->comp_hdr->TD_blk;
2737
9.41M
    int TD_blk_size = BLOCK_SIZE(td_b), new;
2738
9.41M
    char *key;
2739
9.41M
    khint_t k;
2740
2741
9.41M
    if (err) *err = 1;
2742
2743
9.41M
    orig = aux = (char *)bam_aux(b);
2744
2745
2746
    // cF:i  => Extra CRAM bit flags.
2747
    // 1:  Don't auto-decode MD (may be invalid)
2748
    // 2:  Don't auto-decode NM (may be invalid)
2749
9.41M
    if (cf_tag && CRAM_MAJOR_VERS(fd->version) < 4) {
2750
        // Temporary copy of aux so we can amend it.
2751
39.1k
        aux = hts_malloc_ps(sizeof(*aux), aux_size, 4);
2752
39.1k
        if (!aux)
2753
0
            return NULL;
2754
2755
39.1k
        memcpy(aux, orig, aux_size);
2756
39.1k
        aux[aux_size++] = 'c';
2757
39.1k
        aux[aux_size++] = 'F';
2758
39.1k
        aux[aux_size++] = 'C';
2759
39.1k
        aux[aux_size++] = cf_tag;
2760
39.1k
        orig = aux;
2761
39.1k
        aux_end = aux + aux_size;
2762
39.1k
    }
2763
2764
    // Copy aux keys to td_b and aux values to slice aux blocks
2765
9.63M
    while (aux_end - aux >= 1 && aux[0] != 0) {
2766
216k
        int r;
2767
2768
        // Room for code + type + at least 1 byte of data
2769
216k
        if (aux - orig >= aux_size - 3)
2770
14
            goto err;
2771
2772
        // RG:Z
2773
216k
        if (aux[0] == 'R' && aux[1] == 'G' && aux[2] == 'Z') {
2774
1.94k
            char *rg = &aux[3];
2775
1.94k
            aux = rg;
2776
112k
            while (aux < aux_end && *aux++);
2777
1.94k
            if (aux == aux_end && aux[-1] != '\0') {
2778
3
                hts_log_error("Unterminated RG:Z tag for read \"%s\"",
2779
3
                              bam_get_qname(b));
2780
3
                goto err;
2781
3
            }
2782
1.94k
            brg = sam_hrecs_find_rg(fd->header->hrecs, rg);
2783
1.94k
            if (brg) {
2784
560
                continue;
2785
1.38k
            } else {
2786
                // RG:Z tag will be stored verbatim
2787
1.38k
                hts_log_warning("Missing @RG header for RG \"%s\"", rg);
2788
1.38k
                aux = rg - 3;
2789
1.38k
            }
2790
1.94k
        }
2791
2792
        // MD:Z
2793
215k
        if (aux[0] == 'M' && aux[1] == 'D' && aux[2] == 'Z') {
2794
70.8k
            if (cr->len && !no_ref && !(cr->flags & BAM_FUNMAP) && !verbatim_MD) {
2795
22.1k
                if (MD && MD->s && strncasecmp(MD->s, aux+3, orig + aux_size - (aux+3)) == 0) {
2796
6
                    while (aux < aux_end && *aux++);
2797
1
                    if (aux == aux_end && aux[-1] != '\0') {
2798
0
                        hts_log_error("Unterminated MD:Z tag for read \"%s\"",
2799
0
                                      bam_get_qname(b));
2800
0
                        goto err;
2801
0
                    }
2802
1
                    continue;
2803
1
                }
2804
22.1k
            }
2805
70.8k
        }
2806
2807
        // NM:i
2808
215k
        if (aux[0] == 'N' && aux[1] == 'M') {
2809
102
            if (cr->len && !no_ref && !(cr->flags & BAM_FUNMAP) && !verbatim_NM) {
2810
5
                int NM_ = bam_aux2i_end((uint8_t *)aux+2, (uint8_t *)aux_end);
2811
5
                if (NM_ == NM) {
2812
1
                    switch(aux[2]) {
2813
0
                    case 'A': case 'C': case 'c': aux+=4; break;
2814
0
                    case 'S': case 's':           aux+=5; break;
2815
0
                    case 'I': case 'i': case 'f': aux+=7; break;
2816
1
                    default:
2817
1
                        hts_log_error("Unhandled type code for NM tag");
2818
1
                        goto err;
2819
1
                    }
2820
0
                    continue;
2821
1
                }
2822
5
            }
2823
102
        }
2824
2825
215k
        BLOCK_APPEND(td_b, aux, 3);
2826
2827
        // Container level tags_used, for TD series
2828
        // Maps integer key ('X0i') to cram_tag_map struct.
2829
215k
        int key = (((unsigned char *) aux)[0]<<16 |
2830
215k
                   ((unsigned char *) aux)[1]<<8  |
2831
215k
                   ((unsigned char *) aux)[2]);
2832
215k
        k = kh_put(m_tagmap, c->tags_used, key, &r);
2833
215k
        if (-1 == r)
2834
0
            goto err;
2835
215k
        else if (r != 0)
2836
61.1k
            kh_val(c->tags_used, k) = NULL;
2837
2838
215k
        if (r == 1) {
2839
61.1k
            khint_t k_global;
2840
2841
            // Global tags_used for cram_metrics support
2842
61.1k
            pthread_mutex_lock(&fd->metrics_lock);
2843
61.1k
            k_global = kh_put(m_metrics, fd->tags_used, key, &r);
2844
61.1k
            if (-1 == r) {
2845
0
                pthread_mutex_unlock(&fd->metrics_lock);
2846
0
                goto err;
2847
0
            }
2848
61.1k
            if (r >= 1) {
2849
8.69k
                kh_val(fd->tags_used, k_global) = cram_new_metrics();
2850
8.69k
                if (!kh_val(fd->tags_used, k_global)) {
2851
0
                    kh_del(m_metrics, fd->tags_used, k_global);
2852
0
                    pthread_mutex_unlock(&fd->metrics_lock);
2853
0
                    goto err;
2854
0
                }
2855
8.69k
            }
2856
2857
61.1k
            pthread_mutex_unlock(&fd->metrics_lock);
2858
2859
61.1k
            int i2[2] = {'\t',key};
2860
61.1k
            size_t sk = key;
2861
61.1k
            cram_tag_map *m = calloc(1, sizeof(*m));
2862
61.1k
            if (!m)
2863
0
                goto_err;
2864
61.1k
            kh_val(c->tags_used, k) = m;
2865
2866
61.1k
            cram_codec *c;
2867
2868
            // Use a block content id based on the tag id.
2869
            // Codec type depends on tag data type.
2870
61.1k
            switch(aux[2]) {
2871
35.2k
            case 'Z': case 'H':
2872
                // string as byte_array_stop
2873
35.2k
                c = cram_encoder_init(E_BYTE_ARRAY_STOP, NULL,
2874
35.2k
                                      E_BYTE_ARRAY, (void *)i2,
2875
35.2k
                                      fd->version, &fd->vv);
2876
35.2k
                break;
2877
2878
20.9k
            case 'A': case 'c': case 'C': {
2879
                // byte array len, 1 byte
2880
20.9k
                cram_byte_array_len_encoder e;
2881
20.9k
                cram_stats st;
2882
2883
20.9k
                e.len_encoding = E_HUFFMAN;
2884
20.9k
                e.len_dat = NULL; // will get codes from st
2885
2886
20.9k
                memset(&st, 0, sizeof(st));
2887
20.9k
                if (cram_stats_add(&st, 1) < 0) goto block_err;
2888
20.9k
                cram_stats_encoding(fd, &st);
2889
2890
20.9k
                e.val_encoding = E_EXTERNAL;
2891
20.9k
                e.val_dat = (void *)sk;
2892
2893
20.9k
                c = cram_encoder_init(E_BYTE_ARRAY_LEN, &st,
2894
20.9k
                                      E_BYTE_ARRAY, (void *)&e,
2895
20.9k
                                      fd->version, &fd->vv);
2896
20.9k
                break;
2897
20.9k
            }
2898
2899
447
            case 's': case 'S': {
2900
                // byte array len, 2 byte
2901
447
                cram_byte_array_len_encoder e;
2902
447
                cram_stats st;
2903
2904
447
                e.len_encoding = E_HUFFMAN;
2905
447
                e.len_dat = NULL; // will get codes from st
2906
2907
447
                memset(&st, 0, sizeof(st));
2908
447
                if (cram_stats_add(&st, 2) < 0) goto block_err;
2909
447
                cram_stats_encoding(fd, &st);
2910
2911
447
                e.val_encoding = E_EXTERNAL;
2912
447
                e.val_dat = (void *)sk;
2913
2914
447
                c = cram_encoder_init(E_BYTE_ARRAY_LEN, &st,
2915
447
                                      E_BYTE_ARRAY, (void *)&e,
2916
447
                                      fd->version, &fd->vv);
2917
447
                break;
2918
447
            }
2919
2.78k
            case 'i': case 'I': case 'f': {
2920
                // byte array len, 4 byte
2921
2.78k
                cram_byte_array_len_encoder e;
2922
2.78k
                cram_stats st;
2923
2924
2.78k
                e.len_encoding = E_HUFFMAN;
2925
2.78k
                e.len_dat = NULL; // will get codes from st
2926
2927
2.78k
                memset(&st, 0, sizeof(st));
2928
2.78k
                if (cram_stats_add(&st, 4) < 0) goto block_err;
2929
2.78k
                cram_stats_encoding(fd, &st);
2930
2931
2.78k
                e.val_encoding = E_EXTERNAL;
2932
2.78k
                e.val_dat = (void *)sk;
2933
2934
2.78k
                c = cram_encoder_init(E_BYTE_ARRAY_LEN, &st,
2935
2.78k
                                      E_BYTE_ARRAY, (void *)&e,
2936
2.78k
                                      fd->version, &fd->vv);
2937
2.78k
                break;
2938
2.78k
            }
2939
2940
1.51k
            case 'B': {
2941
                // Byte array of variable size, but we generate our tag
2942
                // byte stream at the wrong stage (during reading and not
2943
                // after slice header construction). So we use
2944
                // BYTE_ARRAY_LEN with the length codec being external
2945
                // too.
2946
1.51k
                cram_byte_array_len_encoder e;
2947
2948
1.51k
                e.len_encoding = E_EXTERNAL;
2949
1.51k
                e.len_dat = (void *)sk; // or key+128 for len?
2950
2951
1.51k
                e.val_encoding = E_EXTERNAL;
2952
1.51k
                e.val_dat = (void *)sk;
2953
2954
1.51k
                c = cram_encoder_init(E_BYTE_ARRAY_LEN, NULL,
2955
1.51k
                                      E_BYTE_ARRAY, (void *)&e,
2956
1.51k
                                      fd->version, &fd->vv);
2957
1.51k
                break;
2958
2.78k
            }
2959
2960
205
            default:
2961
205
                hts_log_error("Unsupported SAM aux type '%c'", aux[2]);
2962
205
                c = NULL;
2963
61.1k
            }
2964
2965
61.1k
            if (!c)
2966
205
                goto_err;
2967
2968
60.9k
            m->codec = c;
2969
2970
            // Link to fd-global tag metrics
2971
60.9k
            pthread_mutex_lock(&fd->metrics_lock);
2972
60.9k
            m->m = k_global ? (cram_metrics *)kh_val(fd->tags_used, k_global) : NULL;
2973
60.9k
            pthread_mutex_unlock(&fd->metrics_lock);
2974
60.9k
        }
2975
2976
215k
        cram_tag_map *tm = (cram_tag_map *)kh_val(c->tags_used, k);
2977
215k
        if (!tm) goto_err;
2978
215k
        cram_codec *codec = tm->codec;
2979
215k
        if (!tm->codec) goto_err;
2980
2981
215k
        switch(aux[2]) {
2982
75.2k
        case 'A': case 'C': case 'c':
2983
75.2k
            if (aux_end - aux < 3+1)
2984
0
                goto err;
2985
2986
75.2k
            if (!tm->blk) {
2987
20.9k
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
2988
0
                    goto err;
2989
20.9k
                codec->u.e_byte_array_len.val_codec->out = tm->blk;
2990
20.9k
            }
2991
2992
75.2k
            aux+=3;
2993
            //codec->encode(s, codec, aux, 1);
2994
            // Functionally equivalent, but less code.
2995
75.2k
            BLOCK_APPEND_CHAR(tm->blk, *aux);
2996
75.2k
            aux++;
2997
75.2k
            break;
2998
2999
6.84k
        case 'S': case 's':
3000
6.84k
            if (aux_end - aux < 3+2)
3001
3
                goto err;
3002
3003
6.84k
            if (!tm->blk) {
3004
446
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
3005
0
                    goto err;
3006
446
                codec->u.e_byte_array_len.val_codec->out = tm->blk;
3007
446
            }
3008
3009
6.84k
            aux+=3;
3010
            //codec->encode(s, codec, aux, 2);
3011
6.84k
            BLOCK_APPEND(tm->blk, aux, 2);
3012
6.84k
            aux+=2;
3013
6.84k
            break;
3014
3015
18.7k
        case 'I': case 'i': case 'f':
3016
18.7k
            if (aux_end - aux < 3+4)
3017
2
                goto err;
3018
3019
18.7k
            if (!tm->blk) {
3020
2.77k
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
3021
0
                    goto err;
3022
2.77k
                codec->u.e_byte_array_len.val_codec->out = tm->blk;
3023
2.77k
            }
3024
3025
18.7k
            aux+=3;
3026
            //codec->encode(s, codec, aux, 4);
3027
18.7k
            BLOCK_APPEND(tm->blk, aux, 4);
3028
18.7k
            aux+=4;
3029
18.7k
            break;
3030
3031
0
        case 'd':
3032
0
            if (aux_end - aux < 3+8)
3033
0
                goto err;
3034
3035
0
            if (!tm->blk) {
3036
0
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
3037
0
                    goto err;
3038
0
                codec->u.e_byte_array_len.val_codec->out = tm->blk;
3039
0
            }
3040
3041
0
            aux+=3; //*tmp++=*aux++; *tmp++=*aux++; *tmp++=*aux++;
3042
            //codec->encode(s, codec, aux, 8);
3043
0
            BLOCK_APPEND(tm->blk, aux, 8);
3044
0
            aux+=8;
3045
0
            break;
3046
3047
95.0k
        case 'Z': case 'H': {
3048
95.0k
            if (aux_end - aux < 3)
3049
0
                goto err;
3050
3051
95.0k
            if (!tm->blk) {
3052
35.2k
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
3053
0
                    goto err;
3054
35.2k
                codec->out = tm->blk;
3055
35.2k
            }
3056
3057
95.0k
            char *aux_s;
3058
95.0k
            aux += 3;
3059
95.0k
            aux_s = aux;
3060
17.5M
            while (aux < aux_end && *aux++);
3061
95.0k
            if (aux == aux_end && aux[-1] != '\0') {
3062
1
                hts_log_error("Unterminated %c%c:%c tag for read \"%s\"",
3063
1
                              aux_s[-3], aux_s[-2], aux_s[-1],
3064
1
                              bam_get_qname(b));
3065
1
                goto err;
3066
1
            }
3067
95.0k
            if (codec->encode(s, codec, aux_s, aux - aux_s) < 0)
3068
0
                goto err;
3069
95.0k
            break;
3070
95.0k
        }
3071
3072
95.0k
        case 'B': {
3073
19.7k
            if (aux_end - aux < 4+4)
3074
4
                goto err;
3075
3076
19.7k
            int type = aux[3];
3077
19.7k
            uint64_t count = (((uint64_t)((unsigned char *)aux)[4]) << 0 |
3078
19.7k
                              ((uint64_t)((unsigned char *)aux)[5]) << 8 |
3079
19.7k
                              ((uint64_t)((unsigned char *)aux)[6]) <<16 |
3080
19.7k
                              ((uint64_t)((unsigned char *)aux)[7]) <<24);
3081
19.7k
            uint64_t blen;
3082
19.7k
            if (!tm->blk) {
3083
1.50k
                if (!(tm->blk = cram_new_block(EXTERNAL, key)))
3084
0
                    goto err;
3085
1.50k
                codec->u.e_byte_array_len.len_codec->out = tm->blk;
3086
1.50k
                codec->u.e_byte_array_len.val_codec->out = tm->blk;
3087
1.50k
            }
3088
3089
            // skip TN field
3090
19.7k
            aux+=3;
3091
3092
            // We use BYTE_ARRAY_LEN with external length, so store that first
3093
19.7k
            switch (type) {
3094
2.72k
            case 'c': case 'C':
3095
2.72k
                blen = count;
3096
2.72k
                break;
3097
8.31k
            case 's': case 'S':
3098
8.31k
                blen = 2*count;
3099
8.31k
                break;
3100
8.62k
            case 'i': case 'I': case 'f':
3101
8.62k
                blen = 4*count;
3102
8.62k
                break;
3103
69
            default:
3104
69
                hts_log_error("Unknown sub-type '%c' for aux type 'B'", type);
3105
69
                goto err;
3106
19.7k
            }
3107
3108
19.6k
            blen += 5; // sub-type & length
3109
19.6k
            if (aux_end - aux < blen || blen > INT_MAX)
3110
5
                goto err;
3111
3112
19.6k
            if (codec->encode(s, codec, aux, (int) blen) < 0)
3113
0
                goto err;
3114
19.6k
            aux += blen;
3115
19.6k
            break;
3116
19.6k
        }
3117
0
        default:
3118
0
            hts_log_error("Unknown aux type '%c'", aux_end - aux < 2 ? '?' : aux[2]);
3119
0
            goto err;
3120
215k
        }
3121
215k
        tm->blk->m = tm->m;
3122
215k
    }
3123
3124
    // FIXME: sort BLOCK_DATA(td_b) by char[3] triples
3125
3126
    // And and increment TD hash entry
3127
9.41M
    BLOCK_APPEND_CHAR(td_b, 0);
3128
3129
9.41M
    key = (char *)BLOCK_DATA(td_b) + TD_blk_size;
3130
9.41M
    k = kh_put(m_s2i, c->comp_hdr->TD_hash, key, &new);
3131
9.41M
    if (new < 0) {
3132
0
        goto err;
3133
9.41M
    } else if (new == 0) { // Seen this one before
3134
9.36M
        BLOCK_SIZE(td_b) = TD_blk_size;
3135
9.36M
    } else {
3136
        // New entry.  As BLOCK_DATA() can be realloced, copy the
3137
        // key into a string pool and use this as the key in the hash table.
3138
45.5k
        char *pooled_key = string_ndup(c->comp_hdr->TD_keys,
3139
45.5k
                                       (char *)BLOCK_DATA(td_b) + TD_blk_size,
3140
45.5k
                                       BLOCK_SIZE(td_b) - TD_blk_size);
3141
45.5k
        if (!pooled_key)
3142
0
            goto block_err;
3143
45.5k
        kh_key(c->comp_hdr->TD_hash, k) = pooled_key;
3144
45.5k
        kh_val(c->comp_hdr->TD_hash, k) = c->comp_hdr->nTL;
3145
45.5k
        c->comp_hdr->nTL++;
3146
45.5k
    }
3147
3148
9.41M
    cr->TL = kh_val(c->comp_hdr->TD_hash, k);
3149
9.41M
    if (cram_stats_add(c->stats[DS_TL], cr->TL) < 0)
3150
0
        goto block_err;
3151
3152
9.41M
    if (orig != (char *)bam_aux(b))
3153
39.1k
        free(orig);
3154
3155
9.41M
    if (err) *err = 0;
3156
3157
9.41M
    return brg;
3158
3159
307
 err:
3160
307
 block_err:
3161
307
    if (orig != (char *)bam_aux(b))
3162
42
        free(orig);
3163
307
    return NULL;
3164
307
}
3165
3166
/*
3167
 * During cram_next_container or before the final flush at end of
3168
 * file, we update the current slice headers and increment the slice
3169
 * number to the next slice.
3170
 *
3171
 * See cram_next_container() and cram_close().
3172
 */
3173
35.6k
void cram_update_curr_slice(cram_container *c, int version) {
3174
35.6k
    cram_slice *s = c->slice;
3175
35.6k
    if (c->multi_seq) {
3176
588
        s->hdr->ref_seq_id    = -2;
3177
588
        s->hdr->ref_seq_start = 0;
3178
588
        s->hdr->ref_seq_span  = 0;
3179
35.1k
    } else if (c->curr_ref == -1 && CRAM_ge31(version)) {
3180
        // Spec states span=0, but it broke our range queries.
3181
        // See commit message for this and prior.
3182
19.1k
        s->hdr->ref_seq_id    = -1;
3183
19.1k
        s->hdr->ref_seq_start = 0;
3184
19.1k
        s->hdr->ref_seq_span  = 0;
3185
19.1k
    } else {
3186
15.9k
        s->hdr->ref_seq_id    = c->curr_ref;
3187
15.9k
        s->hdr->ref_seq_start = c->first_base;
3188
15.9k
        s->hdr->ref_seq_span  = MAX(0, c->last_base - c->first_base + 1);
3189
15.9k
    }
3190
35.6k
    s->hdr->num_records   = c->curr_rec;
3191
3192
35.6k
    if (c->curr_slice == 0) {
3193
35.6k
        if (c->ref_seq_id != s->hdr->ref_seq_id)
3194
19.7k
            c->ref_seq_id  = s->hdr->ref_seq_id;
3195
35.6k
        c->ref_seq_start = c->first_base;
3196
35.6k
    }
3197
3198
35.6k
    c->curr_slice++;
3199
35.6k
}
3200
3201
/*
3202
 * Handles creation of a new container or new slice, flushing any
3203
 * existing containers when appropriate.
3204
 *
3205
 * Really this is next slice, which may or may not lead to a new container.
3206
 *
3207
 * Returns cram_container pointer on success
3208
 *         NULL on failure.
3209
 */
3210
35.8k
static cram_container *cram_next_container(cram_fd *fd, bam_seq_t *b) {
3211
35.8k
    cram_container *c = fd->ctr;
3212
35.8k
    int i;
3213
3214
    /* First occurrence */
3215
35.8k
    if (c->curr_ref == -2)
3216
5.56k
        c->curr_ref = bam_ref(b);
3217
3218
35.8k
    if (c->slice)
3219
30.2k
        cram_update_curr_slice(c, fd->version);
3220
3221
    /* Flush container */
3222
35.8k
    if (c->curr_slice == c->max_slice ||
3223
30.2k
        (bam_ref(b) != c->curr_ref && !c->multi_seq)) {
3224
30.2k
        c->ref_seq_span = fd->last_base - c->ref_seq_start + 1;
3225
30.2k
        hts_log_info("Flush container %d/%"PRId64"..%"PRId64,
3226
30.2k
                     c->ref_seq_id, c->ref_seq_start,
3227
30.2k
                     c->ref_seq_start + c->ref_seq_span -1);
3228
3229
        /* Encode slices */
3230
30.2k
        if (-1 == cram_flush_container_mt(fd, c))
3231
117
            return NULL;
3232
30.1k
        if (!fd->pool) {
3233
            // Move to sep func, as we need cram_flush_container for
3234
            // the closing phase to flush the partial container.
3235
60.2k
            for (i = 0; i < c->max_slice; i++) {
3236
30.1k
                cram_free_slice(c->slices[i]);
3237
30.1k
                c->slices[i] = NULL;
3238
30.1k
            }
3239
3240
30.1k
            c->slice = NULL;
3241
30.1k
            c->curr_slice = 0;
3242
3243
            /* Easy approach for purposes of freeing stats */
3244
30.1k
            cram_free_container(c);
3245
30.1k
        }
3246
3247
30.1k
        c = fd->ctr = cram_new_container(fd->seqs_per_slice,
3248
30.1k
                                         fd->slices_per_container);
3249
30.1k
        if (!c)
3250
0
            return NULL;
3251
3252
30.1k
        pthread_mutex_lock(&fd->ref_lock);
3253
30.1k
        c->no_ref = fd->no_ref;
3254
30.1k
        c->embed_ref = fd->embed_ref;
3255
30.1k
        c->record_counter = fd->record_counter;
3256
30.1k
        pthread_mutex_unlock(&fd->ref_lock);
3257
30.1k
        c->curr_ref = bam_ref(b);
3258
30.1k
    }
3259
3260
35.6k
    c->last_pos = c->first_base = c->last_base = bam_pos(b)+1;
3261
3262
    /* New slice */
3263
35.6k
    c->slice = c->slices[c->curr_slice] =
3264
35.6k
        cram_new_slice(MAPPED_SLICE, c->max_rec);
3265
35.6k
    if (!c->slice)
3266
0
        return NULL;
3267
3268
35.6k
    if (c->multi_seq) {
3269
0
        c->slice->hdr->ref_seq_id = -2;
3270
0
        c->slice->hdr->ref_seq_start = 0;
3271
0
        c->slice->last_apos = 1;
3272
35.6k
    } else {
3273
35.6k
        c->slice->hdr->ref_seq_id = bam_ref(b);
3274
        // wrong for unsorted data, will fix during encoding.
3275
35.6k
        c->slice->hdr->ref_seq_start = bam_pos(b)+1;
3276
35.6k
        c->slice->last_apos = bam_pos(b)+1;
3277
35.6k
    }
3278
3279
35.6k
    c->curr_rec = 0;
3280
35.6k
    c->s_num_bases = 0;
3281
35.6k
    c->n_mapped = 0;
3282
3283
    // QO field: 0 implies original orientation, 1 implies sequence orientation
3284
    // 1 is often preferable for NovaSeq, but impact is slight. ~0.5% diff.
3285
    // Conversely other data sets it's often better than 1% saving for 0.
3286
    // This was a V4.0 option, but we retain the check as it's potentially an
3287
    // easy win (iff using fqzcomp) for a hypothetical V3.2.
3288
35.6k
    c->qs_seq_orient = 1;
3289
3290
35.6k
    return c;
3291
35.6k
}
3292
3293
3294
/*
3295
 * Converts a single bam record into a cram record.
3296
 * Possibly used within a thread.
3297
 *
3298
 * Returns 0 on success;
3299
 *        -1 on failure
3300
 */
3301
static int process_one_read(cram_fd *fd, cram_container *c,
3302
                            cram_slice *s, cram_record *cr,
3303
                            bam_seq_t *b, int rnum, kstring_t *MD,
3304
9.41M
                            int embed_ref, int no_ref) {
3305
9.41M
    int i, fake_qual = -1, NM = 0;
3306
9.41M
    char *cp;
3307
9.41M
    char *ref, *seq, *qual;
3308
3309
    // Any places with N in seq and/or reference can lead to ambiguous
3310
    // interpretation of the SAM NM:i tag.  So we store these verbatim
3311
    // to ensure valid data round-trips the same regardless of who
3312
    // defines it as valid.
3313
    // Similarly when alignments go beyond end of the reference.
3314
9.41M
    int verbatim_NM = fd->store_nm;
3315
9.41M
    int verbatim_MD = fd->store_md;
3316
3317
    // FIXME: multi-ref containers
3318
3319
9.41M
    cr->flags       = bam_flag(b);
3320
9.41M
    cr->len         = bam_seq_len(b);
3321
9.41M
    uint8_t *md;
3322
9.41M
    if (!(md = bam_aux_get(b, "MD")))
3323
9.34M
        MD = NULL;
3324
69.6k
    else
3325
69.6k
        MD->l = 0;
3326
3327
9.41M
    int cf_tag = 0;
3328
3329
9.41M
    if (embed_ref == 2) {
3330
39.2k
        cf_tag  = MD ? 0 : 1;                   // No MD
3331
39.2k
        cf_tag |= bam_aux_get(b, "NM") ? 0 : 2; // No NM
3332
39.2k
    }
3333
3334
    //fprintf(stderr, "%s => %d\n", rg ? rg : "\"\"", cr->rg);
3335
3336
9.41M
    ref = c->ref ? c->ref - (c->ref_start-1) : NULL;
3337
9.41M
    cr->ref_id      = bam_ref(b);
3338
9.41M
    if (cram_stats_add(c->stats[DS_RI], cr->ref_id) < 0)
3339
0
        goto block_err;
3340
9.41M
    if (cram_stats_add(c->stats[DS_BF], fd->cram_flag_swap[cr->flags & 0xfff]) < 0)
3341
0
        goto block_err;
3342
3343
    // Non reference based encoding means storing the bases verbatim as features, which in
3344
    // turn means every base also has a quality already stored.
3345
9.41M
    if (!no_ref || CRAM_MAJOR_VERS(fd->version) >= 3)
3346
9.41M
        cr->cram_flags |= CRAM_FLAG_PRESERVE_QUAL_SCORES;
3347
3348
9.41M
    if (cr->len <= 0 && CRAM_MAJOR_VERS(fd->version) >= 3)
3349
9.03M
        cr->cram_flags |= CRAM_FLAG_NO_SEQ;
3350
    //cram_stats_add(c->stats[DS_CF], cr->cram_flags & CRAM_FLAG_MASK);
3351
3352
9.41M
    c->num_bases   += cr->len;
3353
9.41M
    cr->apos        = bam_pos(b)+1;
3354
9.41M
    if (cr->apos < 0 || cr->apos > INT64_MAX/2)
3355
62
        goto err;
3356
9.41M
    if (c->pos_sorted) {
3357
9.39M
        if (cr->apos < s->last_apos && !fd->ap_delta) {
3358
404
            c->pos_sorted = 0;
3359
9.39M
        } else {
3360
9.39M
            if (cram_stats_add(c->stats[DS_AP], cr->apos - s->last_apos) < 0)
3361
0
                goto block_err;
3362
9.39M
            s->last_apos = cr->apos;
3363
9.39M
        }
3364
9.39M
    } else {
3365
        //cram_stats_add(c->stats[DS_AP], cr->apos);
3366
23.1k
    }
3367
9.41M
    c->max_apos += (cr->apos > c->max_apos) * (cr->apos - c->max_apos);
3368
3369
    /*
3370
     * This seqs_ds is largely pointless and it could reuse the same memory
3371
     * over and over.
3372
     * s->base_blk is what we need for encoding.
3373
     */
3374
9.41M
    cr->seq         = BLOCK_SIZE(s->seqs_blk);
3375
9.41M
    cr->qual        = BLOCK_SIZE(s->qual_blk);
3376
9.41M
    BLOCK_GROW(s->seqs_blk, cr->len+1);
3377
9.41M
    BLOCK_GROW(s->qual_blk, cr->len);
3378
3379
    // Convert BAM nibble encoded sequence to string of base pairs
3380
9.41M
    seq = cp = (char *)BLOCK_END(s->seqs_blk);
3381
9.41M
    *seq = 0;
3382
9.41M
    nibble2base(bam_seq(b), cp, cr->len);
3383
9.41M
    BLOCK_SIZE(s->seqs_blk) += cr->len;
3384
3385
9.41M
    qual = cp = (char *)bam_qual(b);
3386
3387
3388
    /* Copy and parse */
3389
9.41M
    if (!(cr->flags & BAM_FUNMAP)) {
3390
48.7k
        uint32_t *cig_to, *cig_from;
3391
48.7k
        int64_t apos = cr->apos-1, spos = 0;
3392
48.7k
        int64_t MD_last = apos; // last position of edit in MD tag
3393
3394
48.7k
        if (apos < 0) {
3395
3
            hts_log_error("Mapped read with position <= 0 is disallowed");
3396
3
            return -1;
3397
3
        }
3398
3399
48.7k
        cr->cigar       = s->ncigar;
3400
48.7k
        cr->ncigar      = bam_cigar_len(b);
3401
48.7k
        while (cr->cigar + cr->ncigar >= s->cigar_alloc) {
3402
23
            s->cigar_alloc = s->cigar_alloc ? s->cigar_alloc*2 : 1024;
3403
23
            uint32_t *cigar
3404
23
                = hts_realloc_p(s->cigar, sizeof(*s->cigar), s->cigar_alloc);
3405
23
            if (!cigar)
3406
0
                return -1;
3407
23
            s->cigar = cigar;
3408
23
        }
3409
3410
48.7k
        cig_to = (uint32_t *)s->cigar;
3411
48.7k
        cig_from = (uint32_t *)bam_cigar(b);
3412
3413
48.7k
        cr->feature = 0;
3414
48.7k
        cr->nfeature = 0;
3415
174k
        for (i = 0; i < cr->ncigar; i++) {
3416
126k
            enum cigar_op cig_op = cig_from[i] & BAM_CIGAR_MASK;
3417
126k
            uint32_t cig_len = cig_from[i] >> BAM_CIGAR_SHIFT;
3418
126k
            cig_to[i] = cig_from[i];
3419
3420
            /* Can also generate events from here for CRAM diffs */
3421
3422
126k
            switch (cig_op) {
3423
0
                int l;
3424
3425
                // Don't trust = and X ops to be correct.
3426
26.9k
            case BAM_CMATCH:
3427
27.1k
            case BAM_CBASE_MATCH:
3428
30.0k
            case BAM_CBASE_MISMATCH:
3429
                //fprintf(stderr, "\nBAM_CMATCH\nR: %.*s\nS: %.*s\n",
3430
                //      cig_len, &ref[apos], cig_len, &seq[spos]);
3431
30.0k
                l = 0;
3432
30.0k
                if (!no_ref && cr->len) {
3433
22.9k
                    int end = cig_len+apos < c->ref_end
3434
22.9k
                        ? cig_len : c->ref_end - apos;
3435
22.9k
                    char *sp = &seq[spos];
3436
22.9k
                    char *rp = &ref[apos];
3437
22.9k
                    char *qp = &qual[spos];
3438
22.9k
                    if (end > cr->len) {
3439
4
                        hts_log_error("CIGAR and query sequence are of different length");
3440
4
                        return -1;
3441
4
                    }
3442
60.3k
                    for (l = 0; l < end; l++) {
3443
                        // This case is just too disputed and different tools
3444
                        // interpret these in different ways.  We give up and
3445
                        // store verbatim.
3446
37.4k
                        if (rp[l] == 'N' && sp[l] == 'N')
3447
9.90k
                            verbatim_NM = verbatim_MD = 1;
3448
37.4k
                        if (rp[l] != sp[l]) {
3449
                            // Build our own MD tag if one is on the sequence, so
3450
                            // we can ensure it matches and thus can be discarded.
3451
27.3k
                            if (MD && ref) {
3452
27.2k
                                if (kputuw(apos+l - MD_last, MD) < 0) goto err;
3453
27.2k
                                if (kputc(rp[l], MD) < 0) goto err;
3454
27.2k
                                MD_last = apos+l+1;
3455
27.2k
                            }
3456
27.3k
                            NM++;
3457
27.3k
                            if (!sp[l])
3458
0
                                break;
3459
27.3k
                            if (0 && CRAM_MAJOR_VERS(fd->version) >= 3) {
3460
#if 0
3461
                                // Disabled for the time being as it doesn't
3462
                                // seem to gain us much.
3463
                                int ol=l;
3464
                                while (l<end && rp[l] != sp[l])
3465
                                    l++;
3466
                                if (l-ol > 1) {
3467
                                    if (cram_add_bases(fd, c, s, cr, spos+ol,
3468
                                                       l-ol, &seq[spos+ol]))
3469
                                        return -1;
3470
                                    l--;
3471
                                } else {
3472
                                    l = ol;
3473
                                    if (cram_add_substitution(fd, c, s, cr,
3474
                                                              spos+l, sp[l],
3475
                                                              qp[l], rp[l]))
3476
                                        return -1;
3477
                                }
3478
#else
3479
                                // With urmap pushed to the limit and lots
3480
                                // of unaligned data (should be soft-clipped)
3481
                                // this saves ~2-7%. Worth it?
3482
0
                                int nl = l;
3483
0
                                int max_end = nl, max_score = 0, score = 0;
3484
0
                                while (nl < end) {
3485
0
                                    if (rp[nl] != sp[nl]) {
3486
0
                                        score += 3;
3487
0
                                        if (max_score < score) {
3488
0
                                            max_score = score;
3489
0
                                            max_end = nl;
3490
0
                                        }
3491
0
                                    } else {
3492
0
                                        score--;
3493
0
                                        if (score < -2 ||
3494
0
                                            max_score - score > 7)
3495
0
                                            break;
3496
0
                                    }
3497
0
                                    nl++;
3498
0
                                }
3499
0
                                if (max_score > 20) {
3500
0
                                    cram_add_bases(fd, c, s, cr, spos+l,
3501
0
                                                   max_end-l, &seq[spos+l]);
3502
0
                                    l = max_end-1;
3503
0
                                } else {
3504
0
                                    while (l < nl) {
3505
0
                                        if (rp[l] != sp[l])
3506
0
                                            cram_add_substitution(fd, c, s,
3507
0
                                                                  cr, spos+l,
3508
0
                                                                  sp[l], qp[l],
3509
0
                                                                  rp[l]);
3510
0
                                        l++;
3511
0
                                    }
3512
0
                                    l--;
3513
0
                                }
3514
0
#endif
3515
27.3k
                            } else {
3516
27.3k
                                if (cram_add_substitution(fd, c, s, cr, spos+l,
3517
27.3k
                                                          sp[l], qp[l], rp[l]))
3518
0
                                    return -1;
3519
27.3k
                            }
3520
27.3k
                        }
3521
37.4k
                    }
3522
22.9k
                    spos += l;
3523
22.9k
                    apos += l;
3524
22.9k
                }
3525
3526
30.0k
                if (l < cig_len && cr->len) {
3527
6.63k
                    if (no_ref) {
3528
2.32k
                        if (CRAM_MAJOR_VERS(fd->version) == 3) {
3529
2.32k
                            if (cram_add_bases(fd, c, s, cr, spos,
3530
2.32k
                                               cig_len-l, &seq[spos]))
3531
0
                                return -1;
3532
2.32k
                            spos += cig_len-l;
3533
2.32k
                        } else {
3534
0
                            for (; l < cig_len && seq[spos]; l++, spos++) {
3535
0
                                if (cram_add_base(fd, c, s, cr, spos,
3536
0
                                                  seq[spos], qual[spos]))
3537
0
                                    return -1;
3538
0
                            }
3539
0
                        }
3540
4.31k
                    } else {
3541
                        /* off end of sequence or non-ref based output */
3542
4.31k
                        verbatim_NM = verbatim_MD = 1;
3543
38.7k
                        for (; l < cig_len && seq[spos]; l++, spos++) {
3544
34.4k
                            if (cram_add_base(fd, c, s, cr, spos,
3545
34.4k
                                              seq[spos], qual[spos]))
3546
0
                                return -1;
3547
34.4k
                        }
3548
4.31k
                    }
3549
6.63k
                    apos += cig_len;
3550
23.4k
                } else if (!cr->len) {
3551
                    /* Seq "*" */
3552
3.99k
                    verbatim_NM = verbatim_MD = 1;
3553
3.99k
                    apos += cig_len;
3554
3.99k
                    spos += cig_len;
3555
3.99k
                }
3556
30.0k
                break;
3557
3558
42.3k
            case BAM_CDEL:
3559
42.3k
                if (MD && ref) {
3560
35.9k
                    if (kputuw(apos - MD_last, MD) < 0) goto err;
3561
35.9k
                    if (apos < c->ref_end) {
3562
19.6k
                        if (kputc_('^', MD) < 0) goto err;
3563
19.6k
                        if (kputsn(&ref[apos], MIN(c->ref_end - apos, cig_len), MD) < 0)
3564
0
                            goto err;
3565
19.6k
                    }
3566
35.9k
                }
3567
42.3k
                NM += cig_len;
3568
3569
42.3k
                if (cram_add_deletion(c, s, cr, spos, cig_len, &seq[spos]))
3570
0
                    return -1;
3571
42.3k
                apos += cig_len;
3572
42.3k
                MD_last = apos;
3573
42.3k
                break;
3574
3575
964
            case BAM_CREF_SKIP:
3576
964
                if (cram_add_skip(c, s, cr, spos, cig_len, &seq[spos]))
3577
0
                    return -1;
3578
964
                apos += cig_len;
3579
964
                MD_last += cig_len;
3580
964
                break;
3581
3582
499
            case BAM_CINS:
3583
499
                if (cr->len && spos + cig_len > cr->len) {
3584
0
                    if (cr->len >= spos)
3585
0
                        cig_len = cr->len - spos;
3586
0
                    else
3587
0
                        return -1;
3588
0
                }
3589
499
                if (cram_add_insertion(c, s, cr, spos, cig_len,
3590
499
                                       cr->len ? &seq[spos] : NULL))
3591
0
                    return -1;
3592
499
                if (no_ref && cr->len) {
3593
390
                    for (l = 0; l < cig_len; l++, spos++) {
3594
68
                        cram_add_quality(fd, c, s, cr, spos, qual[spos]);
3595
68
                    }
3596
322
                } else {
3597
177
                    spos += cig_len;
3598
177
                }
3599
499
                NM += cig_len;
3600
499
                break;
3601
3602
19.5k
            case BAM_CSOFT_CLIP:
3603
19.5k
                if (cr->len && spos + cig_len > cr->len) {
3604
0
                    if (cr->len >= spos)
3605
0
                        cig_len = cr->len - spos;
3606
0
                    else
3607
0
                        return -1;
3608
0
                }
3609
19.5k
                if (cram_add_softclip(c, s, cr, spos, cig_len,
3610
19.5k
                                      cr->len ? &seq[spos] : NULL,
3611
19.5k
                                      fd->version))
3612
0
                    return -1;
3613
3614
19.5k
                if (no_ref &&
3615
6.81k
                    !(cr->cram_flags & CRAM_FLAG_PRESERVE_QUAL_SCORES)) {
3616
0
                    if (cr->len) {
3617
0
                        for (l = 0; l < cig_len; l++, spos++) {
3618
0
                            cram_add_quality(fd, c, s, cr, spos, qual[spos]);
3619
0
                        }
3620
0
                    } else {
3621
0
                        for (l = 0; l < cig_len; l++, spos++) {
3622
0
                            cram_add_quality(fd, c, s, cr, spos, -1);
3623
0
                        }
3624
0
                    }
3625
19.5k
                } else {
3626
19.5k
                    spos += cig_len;
3627
19.5k
                }
3628
19.5k
                break;
3629
3630
31.9k
            case BAM_CHARD_CLIP:
3631
31.9k
                if (cram_add_hardclip(c, s, cr, spos, cig_len, &seq[spos]))
3632
0
                    return -1;
3633
31.9k
                break;
3634
3635
31.9k
            case BAM_CPAD:
3636
904
                if (cram_add_pad(c, s, cr, spos, cig_len, &seq[spos]))
3637
0
                    return -1;
3638
904
                break;
3639
3640
904
            default:
3641
267
                hts_log_error("Unknown CIGAR op code %d", cig_op);
3642
267
                return -1;
3643
126k
            }
3644
126k
        }
3645
48.4k
        if (cr->len && spos != cr->len) {
3646
3
            hts_log_error("CIGAR and query sequence are of different length");
3647
3
            return -1;
3648
3
        }
3649
48.4k
        fake_qual = spos;
3650
        // Protect against negative length refs (fuzz 382922241)
3651
48.4k
        cr->aend = no_ref ? apos : MIN(apos, MAX(0, c->ref_end));
3652
48.4k
        if (cram_stats_add(c->stats[DS_FN], cr->nfeature) < 0)
3653
0
            goto block_err;
3654
3655
48.4k
        if (MD && ref)
3656
36.7k
            if (kputuw(apos - MD_last, MD) < 0) goto err;
3657
9.36M
    } else {
3658
        // Unmapped
3659
9.36M
        cr->cram_flags |= CRAM_FLAG_PRESERVE_QUAL_SCORES;
3660
9.36M
        cr->cigar  = 0;
3661
9.36M
        cr->ncigar = 0;
3662
9.36M
        cr->nfeature = 0;
3663
9.36M
        cr->aend = MIN(cr->apos, c->ref_end);
3664
508M
        for (i = 0; i < cr->len; i++)
3665
499M
            if (cram_stats_add(c->stats[DS_BA], seq[i]) < 0)
3666
0
                goto block_err;
3667
9.36M
        fake_qual = 0;
3668
9.36M
    }
3669
3670
9.41M
    cr->ntags      = 0; //cram_stats_add(c->stats[DS_TC], cr->ntags);
3671
9.41M
    int err = 0;
3672
9.41M
    sam_hrec_rg_t *brg =
3673
9.41M
        cram_encode_aux(fd, b, c, s, cr, verbatim_NM, verbatim_MD, NM, MD,
3674
9.41M
                        cf_tag, no_ref, &err);
3675
9.41M
    if (err)
3676
307
        goto block_err;
3677
3678
    /* Read group, identified earlier */
3679
9.41M
    if (brg) {
3680
560
        cr->rg = brg->id;
3681
9.41M
    } else if (CRAM_MAJOR_VERS(fd->version) == 1) {
3682
0
        sam_hrec_rg_t *brg = sam_hrecs_find_rg(fd->header->hrecs, "UNKNOWN");
3683
0
        if (!brg) goto block_err;
3684
0
        cr->rg = brg->id;
3685
9.41M
    } else {
3686
9.41M
        cr->rg = -1;
3687
9.41M
    }
3688
9.41M
    if (cram_stats_add(c->stats[DS_RG], cr->rg) < 0)
3689
0
        goto block_err;
3690
3691
    /*
3692
     * Append to the qual block now. We do this here as
3693
     * cram_add_substitution() can generate BA/QS events which need to
3694
     * be in the qual block before we append the rest of the data.
3695
     */
3696
9.41M
    if (cr->cram_flags & CRAM_FLAG_PRESERVE_QUAL_SCORES) {
3697
        /* Special case of seq "*" */
3698
9.41M
        if (cr->len == 0) {
3699
9.03M
            cr->len = fake_qual;
3700
9.03M
            BLOCK_GROW(s->qual_blk, cr->len);
3701
9.03M
            cp = (char *)BLOCK_END(s->qual_blk);
3702
9.03M
            memset(cp, 255, cr->len);
3703
9.03M
        } else {
3704
376k
            BLOCK_GROW(s->qual_blk, cr->len);
3705
376k
            cp = (char *)BLOCK_END(s->qual_blk);
3706
376k
            char *from = (char *)&bam_qual(b)[0];
3707
376k
            char *to = &cp[0];
3708
376k
            memcpy(to, from, cr->len);
3709
3710
            // Store quality in original orientation for better compression.
3711
376k
            if (!c->qs_seq_orient) {
3712
0
                if (cr->flags & BAM_FREVERSE) {
3713
0
                    int i, j;
3714
0
                    for (i = 0, j = cr->len-1; i < j; i++, j--) {
3715
0
                        unsigned char c;
3716
0
                        c = to[i];
3717
0
                        to[i] = to[j];
3718
0
                        to[j] = c;
3719
0
                    }
3720
0
                }
3721
0
            }
3722
376k
        }
3723
9.41M
        BLOCK_SIZE(s->qual_blk) += cr->len;
3724
9.41M
    } else {
3725
0
        if (cr->len == 0)
3726
0
            cr->len = fake_qual >= 0 ? fake_qual : cr->aend - cr->apos + 1;
3727
0
    }
3728
3729
9.41M
    if (cram_stats_add(c->stats[DS_RL], cr->len) < 0)
3730
0
        goto block_err;
3731
3732
    /* Now we know apos and aend both, update mate-pair information */
3733
9.41M
    {
3734
9.41M
        int new;
3735
9.41M
        khint_t k;
3736
9.41M
        int sec = (cr->flags & BAM_FSECONDARY) ? 1 : 0;
3737
3738
        //fprintf(stderr, "Checking %"PRId64"/%.*s\t", rnum,
3739
        //      cr->name_len, DSTRING_STR(s->name_ds)+cr->name);
3740
9.41M
        if (cr->flags & BAM_FPAIRED) {
3741
193k
            k = kh_put(m_s2i, s->pair[sec], bam_name(b), &new);
3742
193k
            if (-1 == new)
3743
0
                return -1;
3744
193k
            else if (new > 0) {
3745
                // bam_name(b) is likely to change, so copy it to a string pool
3746
                // and use that for the hash table key.
3747
22.2k
                char *key = string_ndup(s->pair_keys, bam_name(b), bam_name_len(b));
3748
22.2k
                if (!key)
3749
0
                    return -1;
3750
22.2k
                kh_key(s->pair[sec], k) = key;
3751
22.2k
                kh_val(s->pair[sec], k) = rnum
3752
22.2k
                    | ((unsigned)((cr->flags & BAM_FREAD1)!=0)<<30)
3753
22.2k
                    | ((unsigned)((cr->flags & BAM_FREAD2)!=0)<<31);
3754
22.2k
            }
3755
9.22M
        } else {
3756
9.22M
            new = 1;
3757
9.22M
            k = 0; // Prevents false-positive warning from gcc -Og
3758
9.22M
        }
3759
3760
9.41M
        if (new == 0) {
3761
171k
            cram_record *p = &s->crecs[kh_val(s->pair[sec], k) & ((1<<30)-1)];
3762
171k
            int64_t aleft, aright;
3763
171k
            int sign;
3764
3765
171k
            aleft = MIN(cr->apos, p->apos);
3766
171k
            aright = MAX(cr->aend, p->aend);
3767
171k
            if (cr->apos < p->apos) {
3768
1.09k
                sign = 1;
3769
170k
            } else if (cr->apos > p->apos) {
3770
1.35k
                sign = -1;
3771
168k
            } else if (cr->flags & BAM_FREAD1) {
3772
46.7k
                sign = 1;
3773
121k
            } else {
3774
121k
                sign = -1;
3775
121k
            }
3776
3777
            // Multiple sets of secondary reads means we cannot tell which is
3778
            // which, so we store TLEN etc verbatim.
3779
171k
            int has_r1 = kh_val(s->pair[sec], k) & (1<<30);
3780
171k
            unsigned int has_r2 = kh_val(s->pair[sec], k) & (1u<<31);
3781
171k
            if ((has_r1 && (cr->flags & BAM_FREAD1)) ||
3782
132k
                (has_r2 && (cr->flags & BAM_FREAD2)))
3783
139k
                goto detached;
3784
3785
            // This vs p: tlen, matepos, flags. Permit TLEN 0 and/or TLEN +/-
3786
            // a small amount, if appropriate options set.
3787
31.4k
            if ((!fd->tlen_zero && MAX(bam_mate_pos(b)+1, 0) != p->apos) &&
3788
3.92k
                !(fd->tlen_zero && bam_mate_pos(b) == 0))
3789
3.92k
                goto detached;
3790
3791
27.5k
            if (((bam_flag(b) & BAM_FMUNMAP) != 0) !=
3792
27.5k
                ((p->flags & BAM_FUNMAP) != 0))
3793
4.54k
                goto detached;
3794
3795
23.0k
            if (((bam_flag(b) & BAM_FMREVERSE) != 0) !=
3796
23.0k
                ((p->flags & BAM_FREVERSE) != 0))
3797
6
                goto detached;
3798
3799
3800
            // p vs this: tlen, matepos, flags
3801
23.0k
            if (p->ref_id != cr->ref_id &&
3802
243
                !(fd->tlen_zero && p->ref_id == -1))
3803
243
                goto detached;
3804
3805
22.7k
            if (p->mate_pos != cr->apos &&
3806
10
                !(fd->tlen_zero && p->mate_pos == 0))
3807
10
                goto detached;
3808
3809
22.7k
            if (((p->flags & BAM_FMUNMAP) != 0) !=
3810
22.7k
                ((p->mate_flags & CRAM_M_UNMAP) != 0))
3811
0
                goto detached;
3812
3813
22.7k
            if (((p->flags & BAM_FMREVERSE) != 0) !=
3814
22.7k
                ((p->mate_flags & CRAM_M_REVERSE) != 0))
3815
0
                goto detached;
3816
3817
            // Supplementary reads are just too ill defined
3818
22.7k
            if ((cr->flags & BAM_FSUPPLEMENTARY) ||
3819
22.7k
                (p->flags & BAM_FSUPPLEMENTARY))
3820
2
                goto detached;
3821
3822
            // When in lossy name mode, if a read isn't detached we
3823
            // cannot store the name.  The corollary is that when we
3824
            // must store the name, it must be detached (inefficient).
3825
22.7k
            if (fd->lossy_read_names &&
3826
0
                (!(cr->cram_flags & CRAM_FLAG_DISCARD_NAME) ||
3827
0
                 !((p->cram_flags & CRAM_FLAG_DISCARD_NAME))))
3828
0
                goto detached;
3829
3830
            // Now check TLEN.  We do this last as sometimes it's the
3831
            // only thing that differs.  In CRAM4 we have a better way
3832
            // of handling this that doesn't break detached status
3833
22.7k
            int explicit_tlen = 0;
3834
22.7k
            int tflag1 = ((bam_ins_size(b) &&
3835
14
                           llabs(bam_ins_size(b) - sign*(aright-aleft+1))
3836
14
                           > fd->tlen_approx)
3837
22.7k
                          || (!bam_ins_size(b) && !fd->tlen_zero));
3838
3839
22.7k
            int tflag2 = ((p->tlen && llabs(p->tlen - -sign*(aright-aleft+1))
3840
14
                           > fd->tlen_approx)
3841
22.7k
                          || (!p->tlen && !fd->tlen_zero));
3842
3843
22.7k
            if (tflag1 || tflag2)
3844
22.7k
                goto detached;
3845
3846
            /*
3847
             * The fields below are unused when encoding this read as it is
3848
             * no longer detached.  In theory they may get referred to when
3849
             * processing a 3rd or 4th read in this template?, so we set them
3850
             * here just to be sure.
3851
             *
3852
             * They do not need cram_stats_add() calls those as they are
3853
             * not emitted.
3854
             */
3855
3
            cr->mate_pos = p->apos;
3856
3
            cram_stats_add(c->stats[DS_NP], cr->mate_pos);
3857
3
            cr->tlen = explicit_tlen ? bam_ins_size(b) : sign*(aright-aleft+1);
3858
3
            cram_stats_add(c->stats[DS_TS], cr->tlen);
3859
3
            cr->mate_flags =
3860
3
                ((p->flags & BAM_FMUNMAP)   == BAM_FMUNMAP)   * CRAM_M_UNMAP +
3861
3
                ((p->flags & BAM_FMREVERSE) == BAM_FMREVERSE) * CRAM_M_REVERSE;
3862
3863
            // Decrement statistics aggregated earlier
3864
3
            if (p->cram_flags & CRAM_FLAG_STATS_ADDED) {
3865
3
                cram_stats_del(c->stats[DS_NP], p->mate_pos);
3866
3
                cram_stats_del(c->stats[DS_MF], p->mate_flags);
3867
3
                if (!(p->cram_flags & CRAM_FLAG_EXPLICIT_TLEN)
3868
3
                    && !explicit_tlen)
3869
3
                    cram_stats_del(c->stats[DS_TS], p->tlen);
3870
3
                cram_stats_del(c->stats[DS_NS], p->mate_ref_id);
3871
3
            }
3872
3873
            /* Similarly we could correct the p-> values too, but these will no
3874
             * longer have any code that refers back to them as the new 'p'
3875
             * for this template is our current 'cr'.
3876
             */
3877
            //p->mate_pos = cr->apos;
3878
            //p->mate_flags =
3879
            //  ((cr->flags & BAM_FMUNMAP)   == BAM_FMUNMAP)  * CRAM_M_UNMAP +
3880
            //  ((cr->flags & BAM_FMREVERSE) == BAM_FMREVERSE)* CRAM_M_REVERSE;
3881
            //p->tlen = p->apos - cr->aend;
3882
3883
            // Clear detached from cr flags
3884
3
            cr->cram_flags &= ~CRAM_FLAG_DETACHED;
3885
3
            cr->cram_flags |= explicit_tlen;
3886
3
            if (cram_stats_add(c->stats[DS_CF], cr->cram_flags & CRAM_FLAG_MASK) < 0)
3887
0
                goto block_err;
3888
3889
            // Clear detached from p flags and set downstream
3890
3
            if (p->cram_flags & CRAM_FLAG_STATS_ADDED) {
3891
3
                cram_stats_del(c->stats[DS_CF], p->cram_flags & CRAM_FLAG_MASK);
3892
3
                p->cram_flags &= ~CRAM_FLAG_STATS_ADDED;
3893
3
            }
3894
3895
3
            p->cram_flags  &= ~CRAM_FLAG_DETACHED;
3896
3
            p->cram_flags  |=  CRAM_FLAG_MATE_DOWNSTREAM | explicit_tlen;;
3897
3
            if (cram_stats_add(c->stats[DS_CF], p->cram_flags & CRAM_FLAG_MASK) < 0)
3898
0
                goto block_err;
3899
3900
3
            p->mate_line = rnum - ((kh_val(s->pair[sec], k) & ((1<<30)-1)) + 1);
3901
3
            if (cram_stats_add(c->stats[DS_NF], p->mate_line) < 0)
3902
0
                goto block_err;
3903
3904
3
            int r12_flags = kh_val(s->pair[sec], k) & (3u<<30);
3905
3
            kh_val(s->pair[sec], k) = (unsigned int)rnum | r12_flags
3906
3
                | (((cr->flags & BAM_FREAD1)!=0)<<30)
3907
3
                | ((unsigned)((cr->flags & BAM_FREAD2)!=0)<<31);
3908
9.24M
        } else {
3909
9.41M
        detached:
3910
            //fprintf(stderr, "unpaired\n");
3911
3912
            /* Derive mate flags from this flag */
3913
9.41M
            cr->mate_flags = 0;
3914
9.41M
            if (bam_flag(b) & BAM_FMUNMAP)
3915
180k
                cr->mate_flags |= CRAM_M_UNMAP;
3916
9.41M
            if (bam_flag(b) & BAM_FMREVERSE)
3917
87
                cr->mate_flags |= CRAM_M_REVERSE;
3918
3919
9.41M
            if (cram_stats_add(c->stats[DS_MF], cr->mate_flags) < 0)
3920
0
                goto block_err;
3921
3922
9.41M
            cr->mate_pos    = MAX(bam_mate_pos(b)+1, 0);
3923
9.41M
            if (cram_stats_add(c->stats[DS_NP], cr->mate_pos) < 0)
3924
0
                goto block_err;
3925
3926
9.41M
            cr->tlen        = bam_ins_size(b);
3927
9.41M
            if (cram_stats_add(c->stats[DS_TS], cr->tlen) < 0)
3928
0
                goto block_err;
3929
3930
9.41M
            cr->cram_flags |= CRAM_FLAG_DETACHED;
3931
9.41M
            if (cram_stats_add(c->stats[DS_CF], cr->cram_flags & CRAM_FLAG_MASK) < 0)
3932
0
                goto block_err;
3933
9.41M
            if (cram_stats_add(c->stats[DS_NS], bam_mate_ref(b)) < 0)
3934
0
                goto block_err;
3935
3936
9.41M
            cr->cram_flags |= CRAM_FLAG_STATS_ADDED;
3937
9.41M
        }
3938
9.41M
    }
3939
3940
9.41M
    cr->mqual       = bam_map_qual(b);
3941
9.41M
    if (cram_stats_add(c->stats[DS_MQ], cr->mqual) < 0)
3942
0
        goto block_err;
3943
3944
9.41M
    cr->mate_ref_id = bam_mate_ref(b);
3945
3946
9.41M
    if (!(bam_flag(b) & BAM_FUNMAP)) {
3947
48.3k
        if (c->first_base > cr->apos)
3948
215
            c->first_base = cr->apos;
3949
3950
48.3k
        if (c->last_base < cr->aend)
3951
5.35k
            c->last_base = cr->aend;
3952
48.3k
    }
3953
3954
9.41M
    return 0;
3955
3956
307
 block_err:
3957
369
 err:
3958
369
    return -1;
3959
307
}
3960
3961
/*
3962
 * Write iterator: put BAM format sequences into a CRAM file.
3963
 * We buffer up a containers worth of data at a time.
3964
 *
3965
 * Returns 0 on success
3966
 *        -1 on failure
3967
 */
3968
9.41M
int cram_put_bam_seq(cram_fd *fd, bam_seq_t *b) {
3969
9.41M
    cram_container *c;
3970
9.41M
    int32_t ref_id = bam_ref(b);
3971
3972
9.41M
    if (ref_id < -1 || (ref_id >= 0 &&
3973
52.7k
                        (!fd->refs || ref_id >= fd->refs->nref))) {
3974
0
        hts_log_error("Reference id %" PRId32 " is outside the header range", ref_id);
3975
0
        errno = EINVAL;
3976
0
        return -1;
3977
0
    }
3978
3979
9.41M
    if (!fd->ctr) {
3980
5.56k
        fd->ctr = cram_new_container(fd->seqs_per_slice,
3981
5.56k
                                     fd->slices_per_container);
3982
5.56k
        if (!fd->ctr)
3983
0
            return -1;
3984
5.56k
        fd->ctr->record_counter = fd->record_counter;
3985
3986
5.56k
        pthread_mutex_lock(&fd->ref_lock);
3987
5.56k
        fd->ctr->no_ref = fd->no_ref;
3988
5.56k
        fd->ctr->embed_ref = fd->embed_ref;
3989
5.56k
        pthread_mutex_unlock(&fd->ref_lock);
3990
5.56k
    }
3991
9.41M
    c = fd->ctr;
3992
3993
9.41M
    int embed_ref = c->embed_ref;
3994
3995
9.41M
    if (!c->slice || c->curr_rec == c->max_rec ||
3996
9.41M
        (bam_ref(b) != c->curr_ref && c->curr_ref >= -1) ||
3997
9.37M
        (c->s_num_bases + c->s_aux_bytes >= fd->bases_per_slice)) {
3998
46.8k
        int slice_rec, curr_rec, multi_seq = fd->multi_seq == 1;
3999
46.8k
        int curr_ref = c->slice ? c->curr_ref : bam_ref(b);
4000
4001
        /*
4002
         * Start packing slices when we routinely have under 1/4tr full.
4003
         *
4004
         * This option isn't available if we choose to embed references
4005
         * since we can only have one per slice.
4006
         *
4007
         * The multi_seq var here refers to our intention for the next slice.
4008
         * This slice has already been encoded so we output as-is.
4009
         */
4010
46.8k
        if (fd->multi_seq == -1 && c->curr_rec+8 < (c->max_rec+8)/4 &&
4011
34.7k
            fd->last_slice && fd->last_slice+8 < (c->max_rec+8)/4 &&
4012
28.2k
            embed_ref<=0) {
4013
570
            if (!c->multi_seq)
4014
443
                hts_log_info("Multi-ref enabled for next container");
4015
570
            multi_seq = 1;
4016
46.3k
        } else if (fd->multi_seq == 1) {
4017
11.2k
            pthread_mutex_lock(&fd->metrics_lock);
4018
11.2k
            if (fd->last_RI_count <= c->max_slice && fd->multi_seq_user != 1) {
4019
317
                multi_seq = 0;
4020
317
                hts_log_info("Multi-ref disabled for next container");
4021
317
            }
4022
11.2k
            pthread_mutex_unlock(&fd->metrics_lock);
4023
11.2k
        }
4024
4025
46.8k
        slice_rec = c->slice_rec;
4026
46.8k
        curr_rec  = c->curr_rec;
4027
4028
46.8k
        if (CRAM_MAJOR_VERS(fd->version) == 1 ||
4029
46.8k
            c->curr_rec == c->max_rec || fd->multi_seq != 1 || !c->slice ||
4030
35.8k
            c->s_num_bases + c->s_aux_bytes >= fd->bases_per_slice) {
4031
35.8k
            if (NULL == (c = cram_next_container(fd, b))) {
4032
117
                if (fd->ctr) {
4033
                    // prevent cram_close attempting to flush
4034
117
                    fd->ctr_mt = fd->ctr; // delay free when threading
4035
117
                    fd->ctr = NULL;
4036
117
                }
4037
117
                return -1;
4038
117
            }
4039
35.8k
        }
4040
4041
        /*
4042
         * Due to our processing order, some things we've already done we
4043
         * cannot easily undo. So when we first notice we should be packing
4044
         * multiple sequences per container we emit the small partial
4045
         * container as-is and then start a fresh one in a different mode.
4046
         */
4047
46.7k
        if (multi_seq == 0 && fd->multi_seq == 1 && fd->multi_seq_user == -1) {
4048
            // User selected auto-mode, we're currently using multi-seq, but
4049
            // have detected we don't need to.  Switch back to auto.
4050
317
            fd->multi_seq = -1;
4051
46.4k
        } else if (multi_seq) {
4052
            // We detected we need multi-seq
4053
11.5k
            fd->multi_seq = 1;
4054
11.5k
            c->multi_seq = 1;
4055
11.5k
            c->pos_sorted = 0;
4056
4057
            // Cram_next_container may end up flushing an existing one and
4058
            // triggering fd->embed_ref=2 if no reference is found.
4059
            // Embedded refs are incompatible with multi-seq, so we bail
4060
            // out and switch to no_ref in this scenario.  We do this
4061
            // within the container only, as multi_seq may be temporary
4062
            // and we switch back away from it again.
4063
11.5k
            pthread_mutex_lock(&fd->ref_lock);
4064
11.5k
            if (fd->embed_ref > 0 && c->curr_rec == 0 && c->curr_slice == 0) {
4065
214
                hts_log_warning("Changing from embed_ref to no_ref mode");
4066
                // Should we update fd->embed_ref and no_ref here too?
4067
                // Doing so means if we go into multi-seq and back out
4068
                // again, eg due a cluster of tiny refs in the middle of
4069
                // much larger ones, then we bake in no-ref mode.
4070
                //
4071
                // However for unsorted data we're realistically not
4072
                // going to switch back.
4073
214
                c->embed_ref = fd->embed_ref = 0; // or -1 for auto?
4074
214
                c->no_ref = fd->no_ref = 1;
4075
214
            }
4076
11.5k
            pthread_mutex_unlock(&fd->ref_lock);
4077
4078
11.5k
            if (!c->refs_used) {
4079
588
                pthread_mutex_lock(&fd->ref_lock);
4080
588
                c->refs_used = calloc(fd->refs->nref, sizeof(int));
4081
588
                pthread_mutex_unlock(&fd->ref_lock);
4082
588
                if (!c->refs_used)
4083
0
                    return -1;
4084
588
            }
4085
11.5k
        }
4086
4087
46.7k
        fd->last_slice = curr_rec - slice_rec;
4088
46.7k
        c->slice_rec = c->curr_rec;
4089
4090
        // Have we seen this reference before?
4091
46.7k
        if (bam_ref(b) >= 0 && curr_ref >= 0 && bam_ref(b) != curr_ref &&
4092
0
            embed_ref<=0 && !fd->unsorted && multi_seq) {
4093
4094
0
            if (!c->refs_used) {
4095
0
                pthread_mutex_lock(&fd->ref_lock);
4096
0
                c->refs_used = calloc(fd->refs->nref, sizeof(int));
4097
0
                pthread_mutex_unlock(&fd->ref_lock);
4098
0
                if (!c->refs_used)
4099
0
                    return -1;
4100
0
            } else if (c->refs_used && c->refs_used[bam_ref(b)]) {
4101
0
                pthread_mutex_lock(&fd->ref_lock);
4102
0
                fd->unsorted = 1;
4103
0
                fd->multi_seq = 1;
4104
0
                pthread_mutex_unlock(&fd->ref_lock);
4105
0
            }
4106
0
        }
4107
4108
46.7k
        c->curr_ref = bam_ref(b);
4109
46.7k
        if (c->refs_used && c->curr_ref >= 0) c->refs_used[c->curr_ref]++;
4110
46.7k
    }
4111
4112
9.41M
    if (!c->bams) {
4113
        /* First time through, allocate a set of bam pointers */
4114
35.6k
        pthread_mutex_lock(&fd->bam_list_lock);
4115
35.6k
        if (fd->bl) {
4116
30.1k
            bam_list *spare = fd->bl;
4117
30.1k
            if (c->max_c_rec > spare->nbams) {
4118
0
                bam_seq_t *bams
4119
0
                    = hts_realloc_p(spare->bams, c->max_c_rec,
4120
0
                                    sizeof(*spare->bams));
4121
0
                if (!bams) {
4122
0
                    pthread_mutex_unlock(&fd->bam_list_lock);
4123
0
                    return -1;
4124
0
                }
4125
0
                spare->bams = bams;
4126
0
                int i;
4127
0
                for (i = spare->nbams; i < c->max_c_rec; i++)
4128
0
                    bam_set_mempolicy(&spare->bams[i], BAM_USER_OWNS_STRUCT);
4129
0
                spare->nbams = c->max_c_rec;
4130
0
            }
4131
30.1k
            c->bams = spare->bams;
4132
30.1k
            c->nbams = spare->nbams;
4133
30.1k
            fd->bl = spare->next;
4134
30.1k
            free(spare);
4135
30.1k
        } else {
4136
5.56k
            c->bams = calloc(c->max_c_rec, sizeof(*c->bams));
4137
5.56k
            c->nbams = c->max_c_rec;
4138
5.56k
            if (!c->bams) {
4139
0
                pthread_mutex_unlock(&fd->bam_list_lock);
4140
0
                return -1;
4141
0
            }
4142
5.56k
            int i;
4143
55.6M
            for (i = 0; i < c->max_c_rec; i++)
4144
55.6M
                bam_set_mempolicy(&c->bams[i], BAM_USER_OWNS_STRUCT);
4145
5.56k
        }
4146
35.6k
        pthread_mutex_unlock(&fd->bam_list_lock);
4147
35.6k
    }
4148
4149
    // IDEA: We could have a cram_put_bam_seq_fast which does pointer
4150
    // swapping for bam1_t->data.  The caller would need to accept
4151
    // that the bam object it passes in is modified, but this is often
4152
    // fine if we're doing a read-write loop.
4153
9.41M
    if (bam_copy1(&c->bams[c->curr_c_rec], b) == NULL)
4154
0
        return -1;
4155
9.41M
    if (bam_seq_len(b)) {
4156
377k
        c->s_num_bases += bam_seq_len(b);
4157
9.04M
    } else {
4158
        // No sequence in BAM record.  CRAM doesn't directly support this
4159
        // case, it ends up being stored as a string of N's for each query
4160
        // consuming CIGAR operation.  As this can become very inefficient
4161
        // in time and memory, data where the query length is excessively
4162
        // long are rejected.
4163
9.04M
        hts_pos_t qlen = bam_cigar2qlen(b->core.n_cigar, bam_get_cigar(b));
4164
9.04M
        if (qlen > 100000000) {
4165
204
            hts_log_error("CIGAR query length %"PRIhts_pos
4166
204
                          " for read \"%s\" is too long",
4167
204
                          qlen, bam_get_qname(b));
4168
204
            return -1;
4169
204
        }
4170
9.03M
        c->s_num_bases += qlen;
4171
9.03M
    }
4172
9.41M
    c->curr_rec++;
4173
9.41M
    c->curr_c_rec++;
4174
9.41M
    c->s_aux_bytes += bam_get_l_aux(b);
4175
9.41M
    c->n_mapped += (bam_flag(b) & BAM_FUNMAP) ? 0 : 1;
4176
9.41M
    fd->record_counter++;
4177
4178
9.41M
    return 0;
4179
9.41M
}