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