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 }