mirror of
https://github.com/amitbet/vncproxy.git
synced 2025-04-27 18:55:13 +00:00
192 lines
4.7 KiB
Go
192 lines
4.7 KiB
Go
package encodings
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"io"
|
|
"github.com/amitbet/vncproxy/common"
|
|
"github.com/amitbet/vncproxy/logger"
|
|
)
|
|
|
|
var TightMinToCompress int = 12
|
|
|
|
const (
|
|
TightExplicitFilter = 0x04
|
|
TightFill = 0x08
|
|
TightJpeg = 0x09
|
|
TightPNG = 0x10
|
|
|
|
TightFilterCopy = 0x00
|
|
TightFilterPalette = 0x01
|
|
TightFilterGradient = 0x02
|
|
)
|
|
|
|
type TightEncoding struct {
|
|
bytes []byte
|
|
}
|
|
|
|
func (*TightEncoding) Type() int32 { return int32(common.EncTight) }
|
|
|
|
func calcTightBytePerPixel(pf *common.PixelFormat) int {
|
|
bytesPerPixel := int(pf.BPP / 8)
|
|
|
|
var bytesPerPixelTight int
|
|
if 24 == pf.Depth && 32 == pf.BPP {
|
|
bytesPerPixelTight = 3
|
|
} else {
|
|
bytesPerPixelTight = bytesPerPixel
|
|
}
|
|
return bytesPerPixelTight
|
|
}
|
|
|
|
func (z *TightEncoding) WriteTo(w io.Writer) (n int, err error) {
|
|
return w.Write(z.bytes)
|
|
}
|
|
|
|
func StoreBytes(bytes *bytes.Buffer, data []byte) {
|
|
_, err := bytes.Write(data)
|
|
if err != nil {
|
|
logger.Error("Error in encoding while saving bytes: ", err)
|
|
}
|
|
}
|
|
|
|
func (t *TightEncoding) Read(pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) (common.IEncoding, error) {
|
|
bytesPixel := calcTightBytePerPixel(pixelFmt)
|
|
|
|
r.StartByteCollection()
|
|
defer func() {
|
|
t.bytes = r.EndByteCollection()
|
|
}()
|
|
|
|
compctl, err := r.ReadUint8()
|
|
|
|
if err != nil {
|
|
logger.Errorf("error in handling tight encoding: %v", err)
|
|
return nil, err
|
|
}
|
|
logger.Debugf("bytesPixel= %d, subencoding= %d", bytesPixel, compctl)
|
|
|
|
//move it to position (remove zlib flush commands)
|
|
compType := compctl >> 4 & 0x0F
|
|
|
|
logger.Debugf("afterSHL:%d", compType)
|
|
switch compType {
|
|
case TightFill:
|
|
logger.Debugf("reading fill size=%d\n", bytesPixel)
|
|
//read color
|
|
_, err := r.ReadBytes(int(bytesPixel))
|
|
if err != nil {
|
|
logger.Errorf("error in handling tight encoding: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
return t, nil
|
|
case TightJpeg:
|
|
if pixelFmt.BPP == 8 {
|
|
return nil, errors.New("Tight encoding: JPEG is not supported in 8 bpp mode")
|
|
}
|
|
|
|
len, err := r.ReadCompactLen()
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
logger.Debugf("reading jpeg, size=%d\n", len)
|
|
_, err = r.ReadBytes(len)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return t, nil
|
|
default:
|
|
|
|
if compType > TightJpeg {
|
|
logger.Debug("Compression control byte is incorrect!")
|
|
}
|
|
|
|
handleTightFilters(compctl, pixelFmt, rect, r)
|
|
|
|
return t, nil
|
|
}
|
|
}
|
|
|
|
func handleTightFilters(subencoding uint8, pixelFmt *common.PixelFormat, rect *common.Rectangle, r *common.RfbReadHelper) {
|
|
|
|
var FILTER_ID_MASK uint8 = 0x40
|
|
|
|
var filterid uint8
|
|
var err error
|
|
|
|
if (subencoding & FILTER_ID_MASK) > 0 { // filter byte presence
|
|
filterid, err = r.ReadUint8()
|
|
|
|
if err != nil {
|
|
logger.Errorf("error in handling tight encoding, reading filterid: %v", err)
|
|
return
|
|
}
|
|
logger.Debugf("handleTightFilters: read filter: %d\n", filterid)
|
|
}
|
|
|
|
bytesPixel := calcTightBytePerPixel(pixelFmt)
|
|
|
|
logger.Debugf("handleTightFilters: filter: %d\n", filterid)
|
|
|
|
lengthCurrentbpp := int(bytesPixel) * int(rect.Width) * int(rect.Height)
|
|
|
|
switch filterid {
|
|
case TightFilterPalette: //PALETTE_FILTER
|
|
|
|
colorCount, err := r.ReadUint8()
|
|
if err != nil {
|
|
logger.Errorf("handleTightFilters: error in handling tight encoding, reading TightFilterPalette: %v", err)
|
|
return
|
|
}
|
|
|
|
paletteSize := int(colorCount) + 1 // add one more
|
|
logger.Debugf("handleTightFilters: ----PALETTE_FILTER: paletteSize=%d bytesPixel=%d\n", paletteSize, bytesPixel)
|
|
//complete palette
|
|
_, err = r.ReadBytes(int(paletteSize) * bytesPixel)
|
|
if err != nil {
|
|
logger.Errorf("handleTightFilters: error in handling tight encoding, reading TightFilterPalette.paletteSize: %v", err)
|
|
return
|
|
}
|
|
|
|
var dataLength int
|
|
if paletteSize == 2 {
|
|
dataLength = int(rect.Height) * ((int(rect.Width) + 7) / 8)
|
|
} else {
|
|
dataLength = int(rect.Width) * int(rect.Height)
|
|
}
|
|
_, err = r.ReadTightData(dataLength)
|
|
if err != nil {
|
|
logger.Errorf("handleTightFilters: error in handling tight encoding, Reading Palette: %v", err)
|
|
return
|
|
}
|
|
|
|
case TightFilterGradient: //GRADIENT_FILTER
|
|
logger.Debugf("----GRADIENT_FILTER: bytesPixel=%d\n", bytesPixel)
|
|
logger.Debugf("usegrad: %d\n", filterid)
|
|
_, err := r.ReadTightData(lengthCurrentbpp)
|
|
if err != nil {
|
|
logger.Errorf("handleTightFilters: error in handling tight encoding, Reading GRADIENT_FILTER: %v", err)
|
|
return
|
|
}
|
|
|
|
case TightFilterCopy: //BASIC_FILTER
|
|
//lengthCurrentbpp1 := int(pixelFmt.BPP/8) * int(rect.Width) * int(rect.Height)
|
|
logger.Debugf("handleTightFilters: ----BASIC_FILTER: bytesPixel=%d", bytesPixel)
|
|
|
|
_, err := r.ReadTightData(lengthCurrentbpp)
|
|
if err != nil {
|
|
logger.Errorf("handleTightFilters: error in handling tight encoding, Reading BASIC_FILTER: %v", err)
|
|
return
|
|
}
|
|
|
|
default:
|
|
logger.Errorf("handleTightFilters: Bad tight filter id: %d", filterid)
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|