github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/smime/ber/forkable.go (about)

     1  package ber
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  )
     7  
     8  type forkableWriter struct {
     9  	*bytes.Buffer
    10  	pre, post *forkableWriter
    11  }
    12  
    13  func newForkableWriter() *forkableWriter {
    14  	return &forkableWriter{new(bytes.Buffer), nil, nil}
    15  }
    16  func (f *forkableWriter) fork() (pre, post *forkableWriter) {
    17  	if f.pre != nil || f.post != nil {
    18  		panic("have already forked")
    19  	}
    20  	f.pre = newForkableWriter()
    21  	f.post = newForkableWriter()
    22  	return f.pre, f.post
    23  }
    24  func (f *forkableWriter) Len() (l int) {
    25  	l += f.Buffer.Len()
    26  	if f.pre != nil {
    27  		l += f.pre.Len()
    28  	}
    29  	if f.post != nil {
    30  		l += f.post.Len()
    31  	}
    32  	return
    33  }
    34  
    35  func (f *forkableWriter) writeTo(out io.Writer) (n int, err error) {
    36  	n, err = out.Write(f.Bytes())
    37  	if err != nil {
    38  		return
    39  	}
    40  
    41  	var nn int
    42  
    43  	if f.pre != nil {
    44  		nn, err = f.pre.writeTo(out)
    45  		n += nn
    46  		if err != nil {
    47  			return
    48  		}
    49  	}
    50  
    51  	if f.post != nil {
    52  		nn, err = f.post.writeTo(out)
    53  		n += nn
    54  	}
    55  	return
    56  }
    57  
    58  func marshalHeader(out *forkableWriter, h header) (err error) {
    59  	b := uint8(h.class) << 6
    60  	if h.constructed {
    61  		b |= 0x20
    62  	}
    63  	if h.tag >= 31 {
    64  		b |= 0x1f
    65  		err = out.WriteByte(b)
    66  		if err != nil {
    67  			return
    68  		}
    69  		err = marshalBase128Int(out, int64(h.tag))
    70  		if err != nil {
    71  			return
    72  		}
    73  	} else {
    74  		b |= uint8(h.tag)
    75  		err = out.WriteByte(b)
    76  		if err != nil {
    77  			return
    78  		}
    79  	}
    80  	if h.length >= 128 {
    81  		l := lengthLength(h.length)
    82  		err = out.WriteByte(0x80 | byte(l))
    83  		if err != nil {
    84  			return
    85  		}
    86  		err = marshalLength(out, h.length)
    87  		if err != nil {
    88  			return
    89  		}
    90  	} else {
    91  		err = out.WriteByte(byte(h.length))
    92  		if err != nil {
    93  			return
    94  		}
    95  	}
    96  	return nil
    97  }
    98  
    99  func marshalBase128Int(out *forkableWriter, n int64) (err error) {
   100  	if n == 0 {
   101  		err = out.WriteByte(0)
   102  		return
   103  	}
   104  
   105  	l := 0
   106  	for i := n; i > 0; i >>= 7 {
   107  		l++
   108  	}
   109  
   110  	for i := l - 1; i >= 0; i-- {
   111  		o := byte(n >> uint(i*7))
   112  		o &= 0x7f
   113  		if i != 0 {
   114  			o |= 0x80
   115  		}
   116  		err = out.WriteByte(o)
   117  		if err != nil {
   118  			return
   119  		}
   120  	}
   121  
   122  	return nil
   123  }
   124  
   125  func marshalLength(out *forkableWriter, i int) (err error) {
   126  	n := lengthLength(i)
   127  
   128  	for ; n > 0; n-- {
   129  		err = out.WriteByte(byte(i >> uint((n-1)*8)))
   130  		if err != nil {
   131  			return
   132  		}
   133  	}
   134  
   135  	return nil
   136  }
   137  
   138  func lengthLength(i int) (numBytes int) {
   139  	numBytes = 1
   140  	for i > 255 {
   141  		numBytes++
   142  		i >>= 8
   143  	}
   144  	return
   145  }