github.com/abemedia/appcast@v0.4.0/integrations/apt/deb/encode.go (about) 1 package deb 2 3 import ( 4 "bytes" 5 "encoding" 6 "encoding/hex" 7 "errors" 8 "fmt" 9 "io" 10 "reflect" 11 "strconv" 12 "sync" 13 "time" 14 ) 15 16 var encoders sync.Map //nolint:gochecknoglobals 17 18 type encoder func(io.Writer, reflect.Value) error 19 20 func Marshal(v any) ([]byte, error) { 21 buf := &bytes.Buffer{} 22 if err := NewEncoder(buf).Encode(v); err != nil { 23 return nil, err 24 } 25 return buf.Bytes(), nil 26 } 27 28 type Encoder struct { 29 w io.Writer 30 } 31 32 func NewEncoder(w io.Writer) *Encoder { 33 return &Encoder{w} 34 } 35 36 func (e *Encoder) Encode(v any) error { 37 if v == nil { 38 return errors.New("unsupported type: nil") 39 } 40 41 val := reflect.ValueOf(v) 42 typ := val.Type() 43 44 if enc, ok := encoders.Load(typ); ok { 45 return enc.(encoder)(e.w, val) //nolint:forcetypeassert 46 } 47 48 enc, err := newEncoder(typ) 49 if err != nil { 50 return err 51 } 52 encoders.Store(typ, enc) 53 return enc(e.w, val) 54 } 55 56 //nolint:gochecknoglobals 57 var ( 58 stringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem() 59 marshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() 60 ) 61 62 func newEncoder(typ reflect.Type) (encoder, error) { 63 switch { 64 case typ == dateType: 65 return newDateEncoder(typ) 66 case typ.Implements(marshalerType): 67 return newMarshalerEncoder(typ) 68 case typ.Implements(stringerType): 69 return newStringerEncoder(typ) 70 } 71 72 switch typ.Kind() { 73 case reflect.Ptr: 74 return newPtrEncoder(typ) 75 case reflect.Slice: 76 return newSliceEncoder(typ) 77 case reflect.Struct: 78 return newStructEncoder(typ) 79 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 80 return newIntEncoder(typ) 81 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 82 return newUintEncoder(typ) 83 case reflect.Float32, reflect.Float64: 84 return newFloatEncoder(typ) 85 case reflect.String: 86 return newStringEncoder(typ) 87 case reflect.Array: 88 if typ.Elem().Kind() == reflect.Uint8 { 89 return newByteArrayEncoder(typ) 90 } 91 } 92 return nil, fmt.Errorf("unsupported type: %s", typ) 93 } 94 95 func newStringerEncoder(typ reflect.Type) (encoder, error) { 96 ptr := typ.Kind() == reflect.Pointer 97 return func(w io.Writer, v reflect.Value) error { 98 if ptr && v.IsNil() { 99 return nil 100 } 101 s := v.Interface().(fmt.Stringer).String() //nolint:forcetypeassert 102 if len(s) == 0 { 103 return nil 104 } 105 return encodeText(w, atob(s)) 106 }, nil 107 } 108 109 func newMarshalerEncoder(typ reflect.Type) (encoder, error) { 110 ptr := typ.Kind() == reflect.Pointer 111 return func(w io.Writer, v reflect.Value) error { 112 if ptr && v.IsNil() { 113 return nil 114 } 115 b, err := v.Interface().(encoding.TextMarshaler).MarshalText() 116 if err != nil { 117 return err 118 } 119 if len(b) == 0 { 120 return nil 121 } 122 return encodeText(w, b) 123 }, nil 124 } 125 126 func newPtrEncoder(typ reflect.Type) (encoder, error) { 127 typ = typ.Elem() 128 enc, err := newEncoder(typ) 129 if err != nil { 130 return nil, err 131 } 132 133 return func(w io.Writer, v reflect.Value) error { 134 if v.IsNil() { 135 return nil 136 } 137 return enc(w, v.Elem()) 138 }, nil 139 } 140 141 func newSliceEncoder(typ reflect.Type) (encoder, error) { 142 enc, err := newEncoder(typ.Elem()) 143 if err != nil { 144 return nil, err 145 } 146 147 return func(w io.Writer, v reflect.Value) error { 148 for i := 0; i < v.Len(); i++ { 149 if i != 0 { 150 if _, err := w.Write(nl); err != nil { 151 return err 152 } 153 } 154 if err := enc(w, v.Index(i)); err != nil { 155 return err 156 } 157 } 158 159 return nil 160 }, nil 161 } 162 163 //nolint:gocognit 164 func newStructEncoder(typ reflect.Type) (encoder, error) { 165 encoders := []func(buf *bytes.Buffer, w io.Writer, v reflect.Value) error{} 166 167 for i := 0; i < typ.NumField(); i++ { 168 i := i 169 field := typ.Field(i) 170 171 n := getFieldName(field) 172 if n == "" { 173 continue 174 } 175 name := atob(n) 176 177 enc, err := newEncoder(field.Type) 178 if err != nil { 179 return nil, err 180 } 181 encoders = append(encoders, func(buf *bytes.Buffer, w io.Writer, v reflect.Value) error { 182 if err := enc(buf, v.Field(i)); err != nil { 183 return err 184 } 185 if buf.Len() == 0 { 186 return nil 187 } 188 if _, err = w.Write(name); err != nil { 189 return err 190 } 191 if _, err = w.Write(colon); err != nil { 192 return err 193 } 194 195 // Only write space after colon if content doesn't start with line break. 196 if c, _ := buf.ReadByte(); c != '\n' { 197 if _, err = w.Write(space); err != nil { 198 return err 199 } 200 } 201 _ = buf.UnreadByte() 202 203 if _, err = io.Copy(w, buf); err != nil { 204 return err 205 } 206 _, err = w.Write(nl) 207 return err 208 }) 209 } 210 211 return func(w io.Writer, v reflect.Value) error { 212 buf := bufPool.Get().(*bytes.Buffer) //nolint:forcetypeassert 213 defer bufPool.Put(buf) 214 for _, enc := range encoders { 215 buf.Reset() 216 if err := enc(buf, w, v); err != nil { 217 return err 218 } 219 } 220 return nil 221 }, nil 222 } 223 224 func newDateEncoder(reflect.Type) (encoder, error) { 225 return func(w io.Writer, v reflect.Value) error { 226 t := v.Interface().(time.Time) //nolint:forcetypeassert 227 if t.IsZero() { 228 return nil 229 } 230 _, err := w.Write(atob(t.Format(time.RFC1123))) 231 return err 232 }, nil 233 } 234 235 func newIntEncoder(reflect.Type) (encoder, error) { 236 return func(w io.Writer, v reflect.Value) error { 237 i := v.Int() 238 if i == 0 { 239 return nil 240 } 241 _, err := w.Write(atob(strconv.FormatInt(i, 10))) 242 return err 243 }, nil 244 } 245 246 func newUintEncoder(reflect.Type) (encoder, error) { 247 return func(w io.Writer, v reflect.Value) error { 248 i := v.Uint() 249 if i == 0 { 250 return nil 251 } 252 _, err := w.Write(atob(strconv.FormatUint(i, 10))) 253 return err 254 }, nil 255 } 256 257 func newFloatEncoder(typ reflect.Type) (encoder, error) { 258 bits := typ.Bits() 259 return func(w io.Writer, v reflect.Value) error { 260 f := v.Float() 261 if f == 0 { 262 return nil 263 } 264 _, err := w.Write(atob(strconv.FormatFloat(f, 'f', -1, bits))) 265 return err 266 }, nil 267 } 268 269 func newByteArrayEncoder(typ reflect.Type) (encoder, error) { 270 size := typ.Len() 271 return func(w io.Writer, v reflect.Value) error { 272 var isNonZero bool 273 b := make([]byte, size) 274 for i := 0; i < size; i++ { 275 if n := v.Index(i).Uint(); n > 0 { 276 b[i] = byte(n) 277 isNonZero = true 278 } 279 } 280 if !isNonZero { 281 return nil 282 } 283 _, err := hex.NewEncoder(w).Write(b) 284 return err 285 }, nil 286 } 287 288 func newStringEncoder(reflect.Type) (encoder, error) { 289 return func(w io.Writer, v reflect.Value) error { 290 return encodeText(w, atob(v.String())) 291 }, nil 292 } 293 294 func encodeText(w io.Writer, in []byte) error { 295 if i := bytes.IndexByte(in, '\n'); i == -1 { 296 _, err := w.Write(in) 297 return err 298 } 299 300 out := make([]byte, 0, len(in)+bytes.Count(in, nl)*2) 301 for i, c := range in { 302 if c == '\n' { 303 var last byte 304 for j := i - 1; j > 0; j-- { 305 if l := in[j]; l != '\n' && l != '\r' { 306 break 307 } 308 last = in[j] 309 } 310 if last == '\n' { 311 out = append(out, '.') 312 } 313 out = append(out, '\n', ' ') 314 } else { 315 out = append(out, c) 316 } 317 } 318 319 _, err := w.Write(out) 320 return err 321 }