-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathencoding_hextile.go
More file actions
224 lines (187 loc) · 6.96 KB
/
Copy pathencoding_hextile.go
File metadata and controls
224 lines (187 loc) · 6.96 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
// SPDX-License-Identifier: MIT
// SPDX-FileCopyrightText: Ryan Johnson
package vnc
import (
"encoding/binary"
"io"
)
// HextileEncoding represents the Hextile encoding as defined in RFC 6143 Section 7.7.4.
// Hextile divides rectangles into 16x16 pixel tiles and applies different compression
// techniques to each tile based on its content.
type HextileEncoding struct {
Tiles []HextileTile
}
// HextileTile represents a single 16x16 (or smaller) tile within a Hextile encoding.
type HextileTile struct {
Width uint16
Height uint16
Background Color
// Foreground color for this tile.
Foreground Color
// Colors contains decoded pixel data for raw tiles.
Colors []Color
// Subrectangles contains colored subrectangles for this tile.
Subrectangles []HextileSubrectangle
}
// HextileSubrectangle represents a colored subrectangle within a Hextile tile.
type HextileSubrectangle struct {
// Color is the color of this subrectangle.
Color Color
// X is the horizontal position within the tile (0-15).
X uint8
// Y is the vertical position within the tile (0-15).
Y uint8
// Width is the width of the subrectangle (1-16).
Width uint8
// Height is the height of the subrectangle (1-16).
Height uint8
}
// Hextile encoding constants as defined in RFC 6143.
const (
HextileRaw = 1
HextileBackgroundSpecified = 2
HextileForegroundSpecified = 4
HextileAnySubrects = 8
HextileSubrectsColoured = 16
HextileTileSize = 16
MaxSubrectsPerTile = 255
)
// Type returns the encoding type identifier for Hextile encoding.
func (*HextileEncoding) Type() int32 {
return 5
}
// Read decodes Hextile encoding data from the server.
// - error: EncodingError if the data cannot be read or is invalid
//
// Example usage:
//
// // This method is typically called by the VNC client's message processing loop
// enc := &HextileEncoding{}
// decodedEnc, err := enc.Read(clientConn, rectangle, dataReader)
// if err != nil {
// log.Printf("Failed to decode Hextile encoding: %v", err)
// return
// }
//
// // Process the Hextile encoding
// hextileEnc := decodedEnc.(*HextileEncoding)
//
// // Render each tile to the framebuffer
// tileIndex := 0
// for tileY := uint16(0); tileY < rectangle.Height; tileY += 16 {
// for tileX := uint16(0); tileX < rectangle.Width; tileX += 16 {
// tile := hextileEnc.Tiles[tileIndex]
// renderTile(rectangle.X + tileX, rectangle.Y + tileY, tile)
// tileIndex++
// }
// }
func (*HextileEncoding) Read(c *ClientConn, rect *Rectangle, r io.Reader) (Encoding, error) {
validator := newInputValidator()
if c.FrameBufferWidth > 0 && c.FrameBufferHeight > 0 {
if err := validator.ValidateRectangle(rect.X, rect.Y, rect.Width, rect.Height,
c.FrameBufferWidth, c.FrameBufferHeight); err != nil {
return nil, encodingError("HextileEncoding.Read", "invalid rectangle dimensions", err)
}
}
tilesX := (rect.Width + HextileTileSize - 1) / HextileTileSize
tilesY := (rect.Height + HextileTileSize - 1) / HextileTileSize
totalTiles := int(tilesX * tilesY)
const maxTiles = 100000
if totalTiles > maxTiles {
return nil, encodingError("HextileEncoding.Read", "too many tiles for rectangle", nil)
}
tiles := make([]HextileTile, totalTiles)
tileIndex := 0
var background, foreground Color
for tileY := uint16(0); tileY < tilesY; tileY++ {
for tileX := uint16(0); tileX < tilesX; tileX++ {
tileWidth := uint16(HextileTileSize)
tileHeight := uint16(HextileTileSize)
if tileX*HextileTileSize+HextileTileSize > rect.Width {
tileWidth = rect.Width - tileX*HextileTileSize
}
if tileY*HextileTileSize+HextileTileSize > rect.Height {
tileHeight = rect.Height - tileY*HextileTileSize
}
tile := &tiles[tileIndex]
tile.Width = tileWidth
tile.Height = tileHeight
var subencoding uint8
if err := binary.Read(r, binary.BigEndian, &subencoding); err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read tile subencoding", err)
}
if subencoding&HextileRaw != 0 {
pixelCount := int(tileWidth * tileHeight)
tile.Colors = make([]Color, pixelCount)
for i := 0; i < pixelCount; i++ {
color, err := readPixelColor(r, c.PixelFormat, c.ColorMap)
if err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read raw tile pixel", err)
}
tile.Colors[i] = color
}
} else {
if subencoding&HextileBackgroundSpecified != 0 {
var err error
background, err = readPixelColor(r, c.PixelFormat, c.ColorMap)
if err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read background color", err)
}
}
tile.Background = background
if subencoding&HextileForegroundSpecified != 0 {
var err error
foreground, err = readPixelColor(r, c.PixelFormat, c.ColorMap)
if err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read foreground color", err)
}
}
tile.Foreground = foreground
if subencoding&HextileAnySubrects != 0 {
var numSubrects uint8
if err := binary.Read(r, binary.BigEndian, &numSubrects); err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read subrectangle count", err)
}
if numSubrects > MaxSubrectsPerTile {
return nil, encodingError("HextileEncoding.Read", "too many subrectangles in tile", nil)
}
tile.Subrectangles = make([]HextileSubrectangle, numSubrects)
for i := uint8(0); i < numSubrects; i++ {
subrect := &tile.Subrectangles[i]
if subencoding&HextileSubrectsColoured != 0 {
var err error
subrect.Color, err = readPixelColor(r, c.PixelFormat, c.ColorMap)
if err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read subrectangle color", err)
}
} else {
subrect.Color = foreground
}
var xyData, whData uint8
if err := binary.Read(r, binary.BigEndian, &xyData); err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read subrectangle position", err)
}
if err := binary.Read(r, binary.BigEndian, &whData); err != nil {
return nil, encodingError("HextileEncoding.Read", "failed to read subrectangle dimensions", err)
}
subrect.X = (xyData >> 4) & 0x0F
subrect.Y = xyData & 0x0F
subrect.Width = ((whData >> 4) & 0x0F) + 1
subrect.Height = (whData & 0x0F) + 1
tileWidthU8 := uint8(tileWidth) // #nosec G115 - tileWidth is <= 16
tileHeightU8 := uint8(tileHeight) // #nosec G115 - tileHeight is <= 16
if subrect.X >= tileWidthU8 || subrect.Y >= tileHeightU8 {
return nil, encodingError("HextileEncoding.Read", "subrectangle position outside tile bounds", nil)
}
if uint16(subrect.X)+uint16(subrect.Width) > tileWidth ||
uint16(subrect.Y)+uint16(subrect.Height) > tileHeight {
return nil, encodingError("HextileEncoding.Read", "subrectangle extends outside tile bounds", nil)
}
}
}
}
tileIndex++
}
}
return &HextileEncoding{Tiles: tiles}, nil
}