github.com/astrogo/fitsio@v0.3.0/file.go (about) 1 // Copyright 2015 The astrogo 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 fitsio 6 7 import ( 8 "fmt" 9 "io" 10 "os" 11 ) 12 13 // Mode defines a FITS file access mode (r/w) 14 type Mode int 15 16 const ( 17 ReadOnly Mode = Mode(os.O_RDONLY) // open the file read-only 18 WriteOnly = Mode(os.O_WRONLY) // open the file write-only 19 ReadWrite = Mode(os.O_RDWR) // open the file read-write 20 ) 21 22 // File represents a FITS file. 23 type File struct { 24 dec Decoder 25 enc Encoder 26 name string 27 mode Mode 28 hdus []HDU 29 } 30 31 // Open opens a FITS file in read-only mode. 32 func Open(r io.Reader) (*File, error) { 33 var err error 34 35 type namer interface { 36 Name() string 37 } 38 name := "" 39 if r, ok := r.(namer); ok { 40 name = r.Name() 41 } 42 43 f := &File{ 44 dec: NewDecoder(r), 45 name: name, 46 mode: ReadOnly, 47 hdus: make([]HDU, 0, 1), 48 } 49 50 for { 51 var hdu HDU 52 hdu, err = f.dec.DecodeHDU() 53 if err != nil { 54 if err != io.EOF { 55 return nil, err 56 } 57 err = nil 58 break 59 } 60 f.hdus = append(f.hdus, hdu) 61 } 62 63 return f, err 64 } 65 66 // Create creates a new FITS file in write-only mode 67 func Create(w io.Writer) (*File, error) { 68 var err error 69 type namer interface { 70 Name() string 71 } 72 name := "" 73 if w, ok := w.(namer); ok { 74 name = w.Name() 75 } 76 77 f := &File{ 78 enc: NewEncoder(w), 79 name: name, 80 mode: WriteOnly, 81 hdus: make([]HDU, 0, 1), 82 } 83 84 return f, err 85 } 86 87 // Close releases resources held by a FITS file. 88 // 89 // It does not close the underlying io.Reader or io.Writer. 90 func (f *File) Close() error { 91 f.enc = nil 92 f.dec = nil 93 f.hdus = nil 94 return nil 95 } 96 97 // Mode returns the access-mode of this FITS file 98 func (f *File) Mode() Mode { 99 return f.mode 100 } 101 102 // Name returns the name of the FITS file 103 func (f *File) Name() string { 104 return f.name 105 } 106 107 // HDUs returns the list of all Header-Data Unit blocks in the file 108 func (f *File) HDUs() []HDU { 109 return f.hdus 110 } 111 112 // HDU returns the i-th HDU 113 func (f *File) HDU(i int) HDU { 114 return f.hdus[i] 115 } 116 117 // Get returns the HDU with name `name` or nil 118 func (f *File) Get(name string) HDU { 119 i, hdu := f.gethdu(name) 120 if i < 0 { 121 return nil 122 } 123 return hdu 124 } 125 126 // Has returns whether the File has a HDU with name `name`. 127 func (f *File) Has(name string) bool { 128 i, _ := f.gethdu(name) 129 if i < 0 { 130 return false 131 } 132 return true 133 } 134 135 // get returns the index and HDU of HDU with name `name`. 136 func (f *File) gethdu(name string) (int, HDU) { 137 for i, hdu := range f.hdus { 138 if hdu.Name() == name { 139 return i, hdu 140 } 141 } 142 return -1, nil 143 } 144 145 // Write writes a HDU to file 146 func (f *File) Write(hdu HDU) error { 147 var err error 148 if f.mode != WriteOnly && f.mode != ReadWrite { 149 return fmt.Errorf("fitsio: file not open for write") 150 } 151 152 if len(f.hdus) == 0 { 153 if hdu.Type() != IMAGE_HDU { 154 return fmt.Errorf("fitsio: file has no primary header. create one first") 155 } 156 157 hdr := hdu.Header() 158 if hdr.Get("SIMPLE") == nil { 159 err = hdr.prepend(Card{ 160 Name: "SIMPLE", 161 Value: true, 162 Comment: "primary HDU", 163 }) 164 if err != nil { 165 return err 166 } 167 } 168 } else { 169 switch hdu.Type() { 170 case IMAGE_HDU: 171 img := hdu.(Image) 172 err = img.freeze() 173 if err != nil { 174 return err 175 } 176 177 case ASCII_TBL, BINARY_TBL: 178 tbl := hdu.(*Table) 179 err = tbl.freeze() 180 if err != nil { 181 return err 182 } 183 } 184 } 185 186 err = f.enc.EncodeHDU(hdu) 187 if err != nil { 188 return err 189 } 190 191 err = f.append(hdu) 192 if err != nil { 193 return err 194 } 195 196 return err 197 } 198 199 // append appends an HDU to the list of Header-Data Unit blocks. 200 func (f *File) append(hdu HDU) error { 201 var err error 202 if f.mode != WriteOnly && f.mode != ReadWrite { 203 return fmt.Errorf("fitsio: file not open for write") 204 } 205 206 // mare sure there is only one primary-hdu 207 if _, ok := hdu.(*primaryHDU); ok && len(f.hdus) != 0 { 208 return fmt.Errorf("fitsio: file has already a Primary HDU") 209 } 210 211 f.hdus = append(f.hdus, hdu) 212 return err 213 }