1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// Copyright ©2015 The bíogo Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package csi
import (
"encoding/binary"
"fmt"
"io"
"github.com/biogo/hts/bgzf"
"github.com/biogo/hts/bgzf/index"
)
// WriteTo writes the CSI index to the given io.Writer. Note that
// the csi specification states that the index is stored as BGZF, but
// WriteTo does not perform compression.
func WriteTo(w io.Writer, idx *Index) error {
idx.sort()
err := binary.Write(w, binary.LittleEndian, csiMagic)
if err != nil {
return err
}
_, err = w.Write([]byte{idx.Version})
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, int32(idx.minShift))
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, int32(idx.depth))
if err != nil {
return err
}
err = binary.Write(w, binary.LittleEndian, int32(len(idx.Auxilliary)))
if err != nil {
return err
}
_, err = w.Write(idx.Auxilliary)
if err != nil {
return err
}
binLimit := uint32(((1 << ((idx.depth + 1) * nextBinShift)) - 1) / 7)
err = writeIndices(w, idx.Version, idx.refs, binLimit)
if err != nil {
return err
}
if idx.unmapped != nil {
err = binary.Write(w, binary.LittleEndian, idx.unmapped)
}
return err
}
func writeIndices(w io.Writer, version byte, idx []refIndex, binLimit uint32) error {
err := binary.Write(w, binary.LittleEndian, int32(len(idx)))
if err != nil {
return err
}
for i := range idx {
err = writeBins(w, version, idx[i].bins, idx[i].stats, binLimit)
if err != nil {
return err
}
}
return nil
}
func writeBins(w io.Writer, version byte, bins []bin, stats *index.ReferenceStats, binLimit uint32) error {
n := int32(len(bins))
if stats != nil {
n++
}
err := binary.Write(w, binary.LittleEndian, &n)
if err != nil {
return err
}
for _, b := range bins {
err = binary.Write(w, binary.LittleEndian, b.bin)
if err != nil {
return fmt.Errorf("csi: failed to write bin number: %v", err)
}
err = binary.Write(w, binary.LittleEndian, vOffset(b.left))
if err != nil {
return fmt.Errorf("csi: failed to write left virtual offset: %v", err)
}
if version == 0x2 {
err = binary.Write(w, binary.LittleEndian, b.records)
if err != nil {
return fmt.Errorf("csi: failed to write record count: %v", err)
}
}
err = writeChunks(w, b.chunks)
if err != nil {
return err
}
}
if stats != nil {
return writeStats(w, version, stats, binLimit)
}
return nil
}
func writeChunks(w io.Writer, chunks []bgzf.Chunk) error {
err := binary.Write(w, binary.LittleEndian, int32(len(chunks)))
if err != nil {
return fmt.Errorf("csi: failed to write bin count: %v", err)
}
for _, c := range chunks {
err = binary.Write(w, binary.LittleEndian, vOffset(c.Begin))
if err != nil {
return fmt.Errorf("csi: failed to write chunk begin virtual offset: %v", err)
}
err = binary.Write(w, binary.LittleEndian, vOffset(c.End))
if err != nil {
return fmt.Errorf("csi: failed to write chunk end virtual offset: %v", err)
}
}
return nil
}
func writeStats(w io.Writer, version byte, stats *index.ReferenceStats, binLimit uint32) error {
var err error
statsDummyBin := binLimit + 1
switch version {
case 0x1:
err = binary.Write(w, binary.LittleEndian, [4]uint32{statsDummyBin, 0, 0, 2})
case 0x2:
err = binary.Write(w, binary.LittleEndian, [6]uint32{statsDummyBin, 0, 0, 0, 0, 2})
}
if err != nil {
return fmt.Errorf("csi: failed to write stats bin header: %v", err)
}
err = binary.Write(w, binary.LittleEndian, vOffset(stats.Chunk.Begin))
if err != nil {
return fmt.Errorf("csi: failed to write index stats chunk begin virtual offset: %v", err)
}
err = binary.Write(w, binary.LittleEndian, vOffset(stats.Chunk.End))
if err != nil {
return fmt.Errorf("csi: failed to write index stats chunk end virtual offset: %v", err)
}
err = binary.Write(w, binary.LittleEndian, stats.Mapped)
if err != nil {
return fmt.Errorf("csi: failed to write index stats mapped count: %v", err)
}
err = binary.Write(w, binary.LittleEndian, stats.Unmapped)
if err != nil {
return fmt.Errorf("csi: failed to write index stats unmapped count: %v", err)
}
return nil
}
|