github.com/goplus/llgo@v0.8.3/xtool/ar/writer.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package ar 18 19 import ( 20 "io" 21 "strconv" 22 ) 23 24 // Writer provides sequential writing of an ar archive. 25 // An ar archive is sequence of header file pairs 26 // Call WriteHeader to begin writing a new file, then call Write to supply the file's data 27 // 28 // Example: 29 // archive := ar.NewWriter(writer) 30 // archive.WriteGlobalHeader() 31 // header := new(ar.Header) 32 // header.Size = 15 // bytes 33 // 34 // if err := archive.WriteHeader(header); err != nil { 35 // return err 36 // } 37 // 38 // io.Copy(archive, data) 39 type Writer struct { 40 w io.Writer 41 nb int64 // number of unwritten bytes for the current file entry 42 } 43 44 // Create a new ar writer that writes to w 45 func NewWriter(w io.Writer) *Writer { return &Writer{w: w} } 46 47 func (aw *Writer) numeric(b []byte, x int64) { 48 s := strconv.FormatInt(x, 10) 49 for len(s) < len(b) { 50 s = s + " " 51 } 52 copy(b, []byte(s)) 53 } 54 55 func (aw *Writer) octal(b []byte, x int64) { 56 s := "100" + strconv.FormatInt(x, 8) 57 for len(s) < len(b) { 58 s = s + " " 59 } 60 copy(b, []byte(s)) 61 } 62 63 func (aw *Writer) string(b []byte, str string) { 64 s := str 65 for len(s) < len(b) { 66 s = s + " " 67 } 68 copy(b, []byte(s)) 69 } 70 71 // Writes to the current entry in the ar archive 72 // Returns ErrWriteTooLong if more than header.Size 73 // bytes are written after a call to WriteHeader 74 func (aw *Writer) Write(b []byte) (n int, err error) { 75 if int64(len(b)) > aw.nb { 76 b = b[0:aw.nb] 77 err = errWriteTooLong 78 } 79 n, werr := aw.w.Write(b) 80 aw.nb -= int64(n) 81 if werr != nil { 82 return n, werr 83 } 84 85 if len(b)%2 == 1 { // data size must be aligned to an even byte 86 n2, _ := aw.w.Write([]byte{'\n'}) 87 return n + n2, err 88 } 89 90 return 91 } 92 93 func (aw *Writer) WriteGlobalHeader() error { 94 _, err := aw.w.Write([]byte(globalHeader)) 95 return err 96 } 97 98 // Writes the header to the underlying writer and prepares 99 // to receive the file payload 100 func (aw *Writer) WriteHeader(hdr *Header) error { 101 aw.nb = int64(hdr.Size) 102 header := make([]byte, headerByteSize) 103 s := slicer(header) 104 105 aw.string(s.next(16), hdr.Name) 106 aw.numeric(s.next(12), hdr.ModTime.Unix()) 107 aw.numeric(s.next(6), int64(hdr.Uid)) 108 aw.numeric(s.next(6), int64(hdr.Gid)) 109 aw.octal(s.next(8), hdr.Mode) 110 aw.numeric(s.next(10), hdr.Size) 111 aw.string(s.next(2), "`\n") 112 113 _, err := aw.w.Write(header) 114 115 return err 116 }