github.com/nikandfor/tlog@v0.21.3/tlz/decoder.go (about)

     1  package tlz
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  
     7  	"github.com/nikandfor/errors"
     8  	"github.com/nikandfor/hacked/hfmt"
     9  
    10  	"github.com/nikandfor/tlog/low"
    11  )
    12  
    13  type (
    14  	Decoder struct {
    15  		io.Reader
    16  
    17  		// output
    18  		block []byte
    19  		mask  int
    20  		pos   int64 // output stream pos
    21  
    22  		// current tag
    23  		state    byte
    24  		off, len int
    25  
    26  		// input
    27  		b    []byte
    28  		i    int
    29  		boff int64 // input stream offset to b[0]
    30  	}
    31  
    32  	Dumper struct {
    33  		io.Writer
    34  
    35  		d Decoder
    36  
    37  		GlobalOffset int64
    38  
    39  		b low.Buf
    40  	}
    41  )
    42  
    43  var eUnexpectedEOF = errors.NewNoCaller("need more")
    44  
    45  func NewDecoder(r io.Reader) *Decoder {
    46  	return &Decoder{
    47  		Reader: r,
    48  	}
    49  }
    50  
    51  func NewDecoderBytes(b []byte) *Decoder {
    52  	return &Decoder{
    53  		b: b,
    54  	}
    55  }
    56  
    57  func (d *Decoder) Reset(rd io.Reader) {
    58  	d.ResetBytes(nil)
    59  	d.Reader = rd
    60  }
    61  
    62  func (d *Decoder) ResetBytes(b []byte) {
    63  	d.Reader = nil
    64  
    65  	if b != nil {
    66  		d.b = b
    67  	}
    68  
    69  	d.i = 0
    70  	d.b = d.b[:len(b)]
    71  	d.boff = 0
    72  
    73  	d.state = 0
    74  }
    75  
    76  func (d *Decoder) Read(p []byte) (n int, err error) {
    77  	var m, i int
    78  
    79  	for n < len(p) && err == nil {
    80  		m, i, err = d.read(p[n:], d.i)
    81  
    82  		n += m
    83  		d.i = i
    84  
    85  		if n == len(p) {
    86  			err = nil
    87  			break
    88  		}
    89  
    90  		if err != eUnexpectedEOF { //nolint:errorlint
    91  			continue
    92  		}
    93  
    94  		err = d.more()
    95  		if errors.Is(err, io.EOF) && (d.state != 0 || d.i < len(d.b)) {
    96  			err = io.ErrUnexpectedEOF
    97  		}
    98  	}
    99  
   100  	return n, err
   101  }
   102  
   103  func (d *Decoder) read(p []byte, st int) (n, i int, err error) {
   104  	if d.state != 0 && len(d.block) == 0 {
   105  		return 0, st, errors.New("missed meta")
   106  	}
   107  
   108  	i = st
   109  
   110  	if d.state == 0 {
   111  		i, err = d.readTag(i)
   112  		if err != nil {
   113  			return
   114  		}
   115  	}
   116  
   117  	if d.state == 'l' && i == len(d.b) {
   118  		return 0, i, eUnexpectedEOF
   119  	}
   120  
   121  	end := d.len
   122  	if end > len(p) {
   123  		end = len(p)
   124  	}
   125  
   126  	if d.state == 'l' {
   127  		end = copy(p[:end], d.b[i:])
   128  		i += end
   129  	} else {
   130  		end = copy(p[:end], d.block[d.off&d.mask:])
   131  		d.off += end
   132  	}
   133  
   134  	d.len -= end
   135  
   136  	for n < end {
   137  		m := copy(d.block[int(d.pos)&d.mask:], p[n:end])
   138  		n += m
   139  		d.pos += int64(m)
   140  	}
   141  
   142  	if d.len == 0 {
   143  		d.state = 0
   144  	}
   145  
   146  	return
   147  }
   148  
   149  func (d *Decoder) readTag(st int) (i int, err error) {
   150  	tag, l, i, err := d.tag(d.b, st)
   151  	if err != nil {
   152  		return st, err
   153  	}
   154  
   155  	if tag == Literal && l == Meta {
   156  		return d.readMetaTag(st)
   157  	}
   158  
   159  	switch tag {
   160  	case Literal:
   161  		d.state = 'l'
   162  		d.len = l
   163  	case Copy:
   164  		d.off, i, err = d.roff(d.b, i)
   165  		if err != nil {
   166  			return st, err
   167  		}
   168  
   169  		d.off = int(d.pos) - d.off - l
   170  
   171  		d.state = 'c'
   172  		d.len = l
   173  	default:
   174  		return st, errors.New("unsupported tag: %x", tag)
   175  	}
   176  
   177  	return i, nil
   178  }
   179  
   180  func (d *Decoder) readMetaTag(st int) (i int, err error) {
   181  	_, meta, i, err := d.tag(d.b, st)
   182  	if err != nil {
   183  		return st, err
   184  	}
   185  
   186  	if meta != Meta {
   187  		panic("bad usage")
   188  	}
   189  
   190  	meta, i, err = d.roff(d.b, i)
   191  	if err != nil {
   192  		return st, err
   193  	}
   194  
   195  	switch meta & MetaTagMask {
   196  	case MetaMagic:
   197  		meta &^= MetaTagMask
   198  
   199  		if i+meta > len(d.b) {
   200  			return st, eUnexpectedEOF
   201  		}
   202  
   203  		if !bytes.Equal(d.b[i:i+meta], []byte("tlz")) {
   204  			return st, errors.New("bad magic")
   205  		}
   206  
   207  		i += meta
   208  	case MetaVer:
   209  		meta &^= MetaTagMask
   210  
   211  		if i+meta > len(d.b) {
   212  			return st, eUnexpectedEOF
   213  		}
   214  
   215  		if string(d.b[i:i+meta]) != Version {
   216  			return st, errors.New("incompatible version")
   217  		}
   218  
   219  		i += meta
   220  	case MetaReset:
   221  		meta, i, err = d.roff(d.b, i) // block size log
   222  		if err != nil {
   223  			return st, err
   224  		}
   225  
   226  		bs := 1 << meta
   227  
   228  		if bs > len(d.block) {
   229  			d.block = make([]byte, bs)
   230  		} else {
   231  			d.block = d.block[:bs]
   232  
   233  			for i := 0; i < bs; {
   234  				i += copy(d.block[i:], zeros)
   235  			}
   236  		}
   237  
   238  		d.pos = 0
   239  		d.mask = bs - 1
   240  
   241  		d.state = 0
   242  	default:
   243  		return st, errors.New("unsupported meta: %x", meta)
   244  	}
   245  
   246  	return i, nil
   247  }
   248  
   249  func (d *Decoder) roff(b []byte, st int) (off, i int, err error) {
   250  	if st >= len(b) {
   251  		return 0, st, eUnexpectedEOF
   252  	}
   253  
   254  	i = st
   255  
   256  	off = int(b[i])
   257  	i++
   258  
   259  	switch off {
   260  	case Off1:
   261  		if i+1 > len(b) {
   262  			return off, st, eUnexpectedEOF
   263  		}
   264  
   265  		off = int(b[i])
   266  		i++
   267  	case Off2:
   268  		if i+2 > len(b) {
   269  			return off, st, eUnexpectedEOF
   270  		}
   271  
   272  		off = int(b[i])<<8 | int(b[i+1])
   273  		i += 2
   274  	case Off4:
   275  		if i+4 > len(b) {
   276  			return off, st, eUnexpectedEOF
   277  		}
   278  
   279  		off = int(b[i])<<24 | int(b[i+1])<<16 | int(b[i+2])<<8 | int(b[i+3])
   280  		i += 4
   281  	case Off8:
   282  		if i+8 > len(b) {
   283  			return off, st, eUnexpectedEOF
   284  		}
   285  
   286  		off = int(b[i])<<56 | int(b[i+1])<<48 | int(b[i+2])<<40 | int(b[i+3])<<32 |
   287  			int(b[i+4])<<24 | int(b[i+5])<<16 | int(b[i+6])<<8 | int(b[i+7])
   288  		i += 8
   289  	default:
   290  		// off is embedded
   291  	}
   292  
   293  	return off, i, nil
   294  }
   295  
   296  func (d *Decoder) tag(b []byte, st int) (tag, l, i int, err error) {
   297  	if st >= len(b) {
   298  		return 0, 0, st, eUnexpectedEOF
   299  	}
   300  
   301  	i = st
   302  
   303  	tag = int(b[i]) & TagMask
   304  	l = int(b[i]) & TagLenMask
   305  	i++
   306  
   307  	switch l {
   308  	case Len1:
   309  		if i+1 > len(b) {
   310  			return tag, l, st, eUnexpectedEOF
   311  		}
   312  
   313  		l = int(b[i])
   314  		i++
   315  	case Len2:
   316  		if i+2 > len(b) {
   317  			return tag, l, st, eUnexpectedEOF
   318  		}
   319  
   320  		l = int(b[i])<<8 | int(b[i+1])
   321  		i += 2
   322  	case Len4:
   323  		if i+4 > len(b) {
   324  			return tag, l, st, eUnexpectedEOF
   325  		}
   326  
   327  		l = int(b[i])<<24 | int(b[i+1])<<16 | int(b[i+2])<<8 | int(b[i+3])
   328  		i += 4
   329  	case Len8:
   330  		if i+8 > len(b) {
   331  			return tag, l, st, eUnexpectedEOF
   332  		}
   333  
   334  		l = int(b[i])<<56 | int(b[i+1])<<48 | int(b[i+2])<<40 | int(b[i+3])<<32 |
   335  			int(b[i+4])<<24 | int(b[i+5])<<16 | int(b[i+6])<<8 | int(b[i+7])
   336  		i += 8
   337  	default:
   338  		// l is embedded
   339  	}
   340  
   341  	return tag, l, i, nil
   342  }
   343  
   344  func (d *Decoder) more() (err error) {
   345  	if d.Reader == nil {
   346  		return io.EOF
   347  	}
   348  
   349  	copy(d.b, d.b[d.i:])
   350  	d.b = d.b[:len(d.b)-d.i]
   351  	d.boff += int64(d.i)
   352  	d.i = 0
   353  
   354  	end := len(d.b)
   355  
   356  	if len(d.b) == 0 {
   357  		d.b = make([]byte, 1024)
   358  	} else {
   359  		d.b = append(d.b, 0, 0, 0, 0, 0, 0, 0, 0)
   360  	}
   361  
   362  	d.b = d.b[:cap(d.b)]
   363  
   364  	n, err := d.Reader.Read(d.b[end:])
   365  	//	println("more", d.i, end, end+n, n, len(d.b))
   366  	d.b = d.b[:end+n]
   367  
   368  	if n != 0 && errors.Is(err, io.EOF) {
   369  		err = nil
   370  	}
   371  
   372  	return err
   373  }
   374  
   375  func Dump(p []byte) string {
   376  	var d Dumper
   377  
   378  	_, err := d.Write(p)
   379  	if err != nil {
   380  		return err.Error()
   381  	}
   382  
   383  	return string(d.b)
   384  }
   385  
   386  func NewDumper(w io.Writer) *Dumper {
   387  	return &Dumper{
   388  		Writer: w,
   389  	}
   390  }
   391  
   392  func (w *Dumper) Write(p []byte) (i int, err error) {
   393  	w.b = w.b[:0]
   394  
   395  	var tag, l int
   396  	for i < len(p) {
   397  		if w.GlobalOffset >= 0 {
   398  			w.b = hfmt.Appendf(w.b, "%6x  ", int(w.GlobalOffset)+i)
   399  		}
   400  
   401  		w.b = hfmt.Appendf(w.b, "%4x  ", i)
   402  
   403  		w.b = hfmt.Appendf(w.b, "%6x  ", w.d.pos)
   404  
   405  		tag, l, i, err = w.d.tag(p, i)
   406  		if err != nil {
   407  			return
   408  		}
   409  
   410  		//	println("loop", i, tag>>6, l)
   411  
   412  		switch {
   413  		case l == Meta:
   414  			tag, i, err = w.d.roff(p, i)
   415  			if err != nil {
   416  				return
   417  			}
   418  
   419  			switch tag & MetaTagMask {
   420  			case MetaMagic, MetaVer:
   421  				l = tag &^ MetaTagMask
   422  
   423  				w.b = hfmt.Appendf(w.b, "meta %4x  %q\n", tag, p[i:i+l])
   424  
   425  				i += l
   426  			case MetaReset:
   427  				l, i, err = w.d.roff(p, i)
   428  
   429  				w.b = hfmt.Appendf(w.b, "meta %4x  %x\n", tag, l)
   430  			default:
   431  				return i, errors.New("unsupported meta tag: %x", tag)
   432  			}
   433  		case tag == Literal:
   434  			w.b = hfmt.Appendf(w.b, "lit  %4x        %q\n", l, p[i:i+l])
   435  
   436  			i += l
   437  			w.d.pos += int64(l)
   438  		case tag == Copy:
   439  			var off int
   440  
   441  			off, i, err = w.d.roff(p, i)
   442  			if err != nil {
   443  				return
   444  			}
   445  
   446  			w.d.pos += int64(l)
   447  
   448  			w.b = hfmt.Appendf(w.b, "copy %4x  off %4x (%4x)\n", l, off, off+l)
   449  
   450  		//	off += l
   451  		default:
   452  			panic(tag)
   453  		}
   454  	}
   455  
   456  	w.GlobalOffset += int64(i)
   457  
   458  	if w.Writer != nil {
   459  		_, err = w.Writer.Write(w.b)
   460  	}
   461  
   462  	return i, err
   463  }