23
|
1 ???using System; |
|
2 using System.Collections.Generic; |
|
3 using System.Diagnostics; |
|
4 using System.Drawing; |
|
5 using System.Drawing.Drawing2D; |
|
6 using System.Drawing.Imaging; |
|
7 using System.IO; |
|
8 using System.Net; |
|
9 using System.Net.Sockets; |
|
10 using System.Security.Cryptography; |
|
11 using System.Text; |
|
12 using System.Threading; |
|
13 using System.Windows.Forms; |
|
14 using UCIS.Net.HTTP; |
|
15 |
|
16 namespace UCIS.VNCServer { |
|
17 public class VNCServerManager : IFramebuffer { |
|
18 private VNCFramebuffer fb; |
|
19 private List<VNCServerConnection> clients = new List<VNCServerConnection>(); |
|
20 private VNCServer server; |
|
21 |
|
22 public event MouseEventHandler MouseDown; |
|
23 public event MouseEventHandler MouseMove; |
|
24 public event MouseEventHandler MouseUp; |
|
25 public event KeyEventHandler KeyDown; |
|
26 public event KeyEventHandler KeyUp; |
|
27 |
|
28 public VNCServerManager(int w, int h) : this(w, h, 5901) { } |
|
29 public VNCServerManager(int w, int h, int p) { |
|
30 fb = new VNCFramebuffer(w, h); |
|
31 server = new VNCServer(p); |
|
32 server.ClientConnected += delegate(object sender, VNCClientConnectedEventArgs e) { |
|
33 e.Client.Framebuffer = fb; |
|
34 e.Client.MouseDown += MouseDown; |
|
35 e.Client.MouseMove += MouseMove; |
|
36 e.Client.MouseUp += MouseUp; |
|
37 e.Client.KeyDown += KeyDown; |
|
38 e.Client.KeyUp += KeyUp; |
|
39 e.Client.Disconnected += ClientDisconnected; |
|
40 lock (clients) clients.Add(e.Client); |
|
41 }; |
|
42 server.Listen(); |
|
43 } |
|
44 |
|
45 private void ClientDisconnected(Object sender, EventArgs e) { |
|
46 lock (clients) clients.Remove((VNCServerConnection)sender); |
|
47 } |
|
48 |
|
49 public void Close() { |
|
50 server.Close(); |
|
51 foreach (VNCServerConnection c in clients.ToArray()) c.Close(); |
|
52 } |
|
53 |
|
54 public int Width { |
|
55 get { return fb.Width; } |
|
56 } |
|
57 public int Height { |
|
58 get { return fb.Height; } |
|
59 } |
|
60 public void Clear() { |
|
61 fb.Clear(); |
|
62 } |
|
63 public void DrawImage(Image image, Rectangle srcrect, Point dest) { |
|
64 fb.DrawImage(image, srcrect, dest); |
|
65 } |
|
66 public void DrawPixels(int[] bitmap, int bmwidth, Rectangle srcrect, Point dest) { |
|
67 fb.DrawPixels(bitmap, bmwidth, srcrect, dest); |
|
68 } |
|
69 public void DrawPixels(IntPtr bitmap, int bmwidth, Rectangle srcrect, Point dest) { |
|
70 fb.DrawPixels(bitmap, bmwidth, srcrect, dest); |
|
71 } |
|
72 public void CopyRectangle(Rectangle srcrect, Point dest) { |
|
73 fb.CopyRectangle(srcrect, dest); |
|
74 } |
|
75 public void CopyRectangleTo(Rectangle srcrect, IFramebuffer destbuffer, Point destposition) { |
|
76 fb.CopyRectangleTo(srcrect, destbuffer, destposition); |
|
77 } |
|
78 |
|
79 public void Resize(int w, int h) { |
|
80 fb = new VNCFramebuffer(w, h); |
|
81 foreach (VNCServerConnection c in clients) c.Framebuffer = fb; |
|
82 } |
|
83 } |
|
84 public class VNCFramebufferUpdateEventArgs : EventArgs { |
|
85 public VNCFramebuffer Framebuffer { get; private set; } |
|
86 public Rectangle Area { get; private set; } |
|
87 internal VNCFramebufferUpdateEventArgs(VNCFramebuffer fb, Rectangle a) { |
|
88 this.Framebuffer = fb; |
|
89 this.Area = a; |
|
90 } |
|
91 } |
|
92 public class VNCFramebuffer : IFramebuffer { |
|
93 public event EventHandler<VNCFramebufferUpdateEventArgs> Update; |
|
94 internal Int32[] Framebuffer { get; private set; } |
|
95 public int Width { get; private set; } |
|
96 public int Height { get; private set; } |
|
97 public VNCFramebuffer(int width, int height) { |
|
98 if (width <= 0) throw new ArgumentOutOfRangeException("width"); |
|
99 if (height <= 0) throw new ArgumentOutOfRangeException("height"); |
|
100 this.Width = width; |
|
101 this.Height = height; |
|
102 this.Framebuffer = new Int32[width * height]; |
|
103 } |
|
104 public void Clear() { |
|
105 for (int i = 0; i < Width * Height; i++) Framebuffer[i] = 0; |
|
106 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update; |
|
107 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(0, 0, Width, Height))); |
|
108 } |
|
109 public unsafe void DrawImage(Image image, Rectangle srcrect, Point dest) { |
|
110 if (srcrect.Width == 0 || srcrect.Height == 0) return; |
|
111 fixed (int* fbptr = Framebuffer) { |
|
112 using (Bitmap b = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppRgb, (IntPtr)fbptr)) { |
|
113 using (Graphics g = Graphics.FromImage(b)) { |
|
114 g.CompositingMode = CompositingMode.SourceCopy; |
|
115 g.DrawImage(image, new Rectangle(dest, srcrect.Size), srcrect, GraphicsUnit.Pixel); |
|
116 } |
|
117 } |
|
118 } |
|
119 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update; |
|
120 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(dest, srcrect.Size))); |
|
121 } |
|
122 public void DrawBitmap(Bitmap bitmap, Rectangle srcrect, Point dest) { |
|
123 DrawImage(bitmap, srcrect, dest); |
|
124 } |
|
125 public unsafe void DrawPixels(int[] bitmap, int bmwidth, Rectangle srcrect, Point dest) { |
|
126 fixed (int* bmp = bitmap) DrawPixels(bmp, bmwidth, srcrect, dest); |
|
127 } |
|
128 public unsafe void DrawPixels(IntPtr bitmap, int bmwidth, Rectangle srcrect, Point dest) { |
|
129 DrawPixels((int*)bitmap, bmwidth, srcrect, dest); |
|
130 } |
|
131 public unsafe void DrawPixels(int* bitmap, int bmwidth, Rectangle srcrect, Point dest) { |
|
132 if (srcrect.X < 0 || srcrect.Y < 0 || srcrect.Width < 0 || srcrect.Height < 0) throw new ArgumentOutOfRangeException("srcrect"); |
|
133 if (dest.X < 0 || dest.Y < 0 || dest.X + srcrect.Width > Width || dest.Y + srcrect.Height > Height) throw new ArgumentOutOfRangeException("dest"); |
|
134 if (srcrect.Width == 0 || srcrect.Height == 0) return; |
|
135 int* bmin = bitmap + srcrect.Y * bmwidth + srcrect.X; |
|
136 //Optionally detect regions that have actually changed. This produces many small regions which may slow down the Tight JPEG encoder (and ZLib based codecs) |
|
137 //DrawChangedPixels(Framebuffer, dest.Y * Width + dest.X, bmin, srcrect.Width, srcrect.Height, bmwidth, dest.X, dest.Y); |
|
138 //return; |
|
139 fixed (int* fbptr = Framebuffer) { |
|
140 int* bmout = fbptr + dest.Y * Width + dest.X; |
|
141 for (int y = 0; y < srcrect.Height; y++) { |
|
142 int* bminl = bmin + y * bmwidth; |
|
143 int* bmoutl = bmout + y * Width; |
|
144 for (int x = 0; x < srcrect.Width; x++) { |
|
145 bmoutl[x] = bminl[x]; |
|
146 } |
|
147 } |
|
148 } |
|
149 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update; |
|
150 if (eh != null) eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(dest, srcrect.Size))); |
|
151 } |
|
152 private unsafe void DrawChangedPixels(int[] shadow, int shadowoffset, int* pixels, int width, int height, int bmwidth, int xoffset, int yoffset) { |
|
153 EventHandler<VNCFramebufferUpdateEventArgs> eh = Update; |
|
154 if (eh == null) return; |
|
155 int firstx = -1, lastx = -1, firsty = -1, lasty = -1; |
|
156 for (int y = 0; y < height; y++) { |
|
157 int firstxline = -1, lastxline = -1; |
|
158 for (int x = 0; x < width; x++) { |
|
159 if (shadow[shadowoffset] != *pixels) { |
|
160 if (firstxline == -1) firstxline = x; |
|
161 lastxline = x; |
|
162 shadow[shadowoffset] = *pixels; |
|
163 } |
|
164 shadowoffset++; |
|
165 pixels++; |
|
166 } |
|
167 shadowoffset += Width - width; |
|
168 pixels += bmwidth - width; |
|
169 if (firsty != -1 && firstxline == -1) { |
|
170 eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(firstx + xoffset, firsty + yoffset, lastx - firstx + 1, lasty - firsty + 1))); |
|
171 firsty = lasty = -1; |
|
172 } else if (firstxline != -1) { |
|
173 if (firsty == -1) { |
|
174 firsty = y; |
|
175 firstx = firstxline; |
|
176 lastx = lastxline; |
|
177 } else { |
|
178 if (firstxline < firstx) firstx = firstxline; |
|
179 if (lastxline > lastx) lastx = lastxline; |
|
180 } |
|
181 lasty = y; |
|
182 } |
|
183 } |
|
184 if (firsty != -1) { |
|
185 eh(this, new VNCFramebufferUpdateEventArgs(this, new Rectangle(firstx + xoffset, firsty + yoffset, lastx - firstx + 1, lasty - firsty + 1))); |
|
186 } |
|
187 } |
|
188 public void CopyRectangle(Rectangle srcrect, Point dest) { |
|
189 DrawPixels(Framebuffer, Width, srcrect, dest); |
|
190 } |
|
191 public void CopyRectangleTo(Rectangle srcrect, IFramebuffer destbuffer, Point destposition) { |
|
192 destbuffer.DrawPixels(Framebuffer, Width, srcrect, destposition); |
|
193 } |
|
194 } |
|
195 struct RFBPixelFormat { |
|
196 public Byte BitsPerPixel { get; set; } |
|
197 public Byte ColorDepth { get; set; } |
|
198 public Boolean BigEndian { get; set; } |
|
199 public Boolean TrueColor { get; set; } |
|
200 public UInt16 RedMax { get; set; } |
|
201 public UInt16 GreenMax { get; set; } |
|
202 public UInt16 BlueMax { get; set; } |
|
203 public Byte RedShift { get; set; } |
|
204 public Byte GreenShift { get; set; } |
|
205 public Byte BlueShift { get; set; } |
|
206 } |
|
207 public class VNCClientConnectedEventArgs : EventArgs { |
|
208 public VNCServer Server { get; private set; } |
|
209 public EndPoint RemoteEndPoint { get; private set; } |
|
210 public VNCServerConnection Client { get; private set; } |
|
211 public Boolean Drop { get; set; } |
|
212 public Boolean AllowNoAuthentication { get; set; } |
|
213 public Boolean AllowPasswordAuthentication { get; set; } |
|
214 public VNCClientConnectedEventArgs(VNCServer serv, VNCServerConnection c, EndPoint ep) { |
|
215 this.Server = serv; |
|
216 this.RemoteEndPoint = ep; |
|
217 this.Client = c; |
|
218 this.Drop = false; |
|
219 this.AllowNoAuthentication = true; |
|
220 this.AllowPasswordAuthentication = false; |
|
221 } |
|
222 } |
|
223 public class VNCClientAuthenticationEventArgs : EventArgs { |
|
224 public VNCServerConnection Client { get; private set; } |
|
225 public Boolean Drop { get; set; } |
|
226 public Boolean UsedPasswordAuthentication { get; internal set; } |
|
227 public String DesktopName { get; set; } |
|
228 internal Byte[] VNCAuthChallenge { private get; set; } |
|
229 internal Byte[] VNCAuthResponse { private get; set; } |
|
230 internal VNCClientAuthenticationEventArgs(VNCServerConnection c) { |
|
231 this.Client = c; |
|
232 this.Drop = false; |
|
233 } |
|
234 public Boolean CheckPassword(String password) { |
|
235 return CheckPassword(Encoding.ASCII.GetBytes(password)); |
|
236 } |
|
237 public Boolean CheckPassword(Byte[] password) { |
|
238 Byte[] passwordtransform = new Byte[8]; |
|
239 for (int i = 0; i < 8 && i < password.Length; i++) { |
|
240 Byte a = password[i], b = 0; |
|
241 for (int j = 0; j < 8; j++) b |= (Byte)(((a >> (7 - j)) & 1) << j); |
|
242 passwordtransform[i] = b; |
|
243 } |
|
244 byte[] check; |
|
245 using (DES des = new DESCryptoServiceProvider()) { |
|
246 des.Mode = CipherMode.ECB; |
|
247 des.Padding = PaddingMode.None; |
|
248 using (ICryptoTransform transform = des.CreateEncryptor(passwordtransform, null)) { |
|
249 check = transform.TransformFinalBlock(VNCAuthChallenge, 0, 16); |
|
250 } |
|
251 } |
|
252 for (int i = 0; i < 16; i++) if (VNCAuthResponse[i] != check[i]) return false; |
|
253 return true; |
|
254 } |
|
255 } |
|
256 public class VNCServer { |
|
257 public event EventHandler<VNCClientConnectedEventArgs> ClientConnected; |
|
258 public EndPoint LocalEndPoint { get; protected set; } |
|
259 public Boolean Listening { get; protected set; } |
|
260 private Socket socket = null; |
|
261 public VNCServer() : this(null) { } |
|
262 public VNCServer(int port) : this(new IPEndPoint(IPAddress.Any, port)) { } |
|
263 public VNCServer(EndPoint ep) { |
|
264 LocalEndPoint = ep; |
|
265 } |
|
266 public void Listen() { |
|
267 if (LocalEndPoint == null) throw new ArgumentNullException("LocalEndPoint"); |
|
268 Listen(LocalEndPoint); |
|
269 } |
|
270 public void Listen(int port) { |
|
271 Listen(new IPEndPoint(IPAddress.Any, port)); |
|
272 } |
|
273 public virtual void Listen(EndPoint ep) { |
|
274 if (Listening) throw new InvalidOperationException("The server is already listening"); |
|
275 socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Unspecified); |
|
276 socket.Bind(ep); |
|
277 socket.Listen(5); |
|
278 LocalEndPoint = ep; |
|
279 Listening = true; |
|
280 socket.BeginAccept(AcceptCallback, socket); |
|
281 } |
|
282 public virtual void Close() { |
|
283 if (!Listening) throw new InvalidOperationException("The server is not listening"); |
|
284 Listening = false; |
|
285 socket.Close(); |
|
286 } |
|
287 private void AcceptCallback(IAsyncResult ar) { |
|
288 Socket socket = ar.AsyncState as Socket; |
|
289 try { |
|
290 Socket clientsock = socket.EndAccept(ar); |
|
291 if (clientsock.ProtocolType == ProtocolType.Tcp) clientsock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); |
|
292 ClientAccepted(new VNCServerConnection(clientsock)); |
|
293 } catch (SocketException ex) { |
|
294 Debug.WriteLine(ex); |
|
295 } catch (ObjectDisposedException ex) { |
|
296 Debug.WriteLine(ex); |
|
297 } |
|
298 if (Listening) socket.BeginAccept(AcceptCallback, socket); |
|
299 } |
|
300 protected void ClientAccepted(VNCServerConnection client) { |
|
301 VNCClientConnectedEventArgs clientargs = new VNCClientConnectedEventArgs(this, client, client.RemoteEndPoint); |
|
302 if (ClientConnected != null) ClientConnected(this, clientargs); |
|
303 if (clientargs.Drop) { |
|
304 client.Close(); |
|
305 } else { |
|
306 client.RunAsync(clientargs); |
|
307 } |
|
308 } |
|
309 } |
|
310 public class WebVNCServer : VNCServer { |
|
311 private HTTPServer httpserver; |
|
312 public WebVNCServer() : this(null) { } |
|
313 public WebVNCServer(int port) : this(new IPEndPoint(IPAddress.Any, port)) { } |
|
314 public WebVNCServer(EndPoint ep) : base(ep) { |
|
315 httpserver = new HTTPServer(); |
|
316 httpserver.ContentProvider = new HTTPContentProviderFunction(HandleClient); |
|
317 httpserver.ServeFlashPolicyFile = true; |
|
318 } |
|
319 public override void Listen(EndPoint ep) { |
|
320 httpserver.Listen(ep); |
|
321 } |
|
322 public override void Close() { |
|
323 httpserver.Dispose(); |
|
324 } |
|
325 public void HandleClient(HTTPContext context) { |
|
326 WebSocketPacketStream stream = new WebSocketPacketStream(context); |
|
327 ClientAccepted(new VNCServerConnection(stream, context.Socket)); |
|
328 } |
|
329 } |
|
330 public interface IZLibCompressor { |
|
331 byte[] Compress(Byte[] data, int offset, int count); |
|
332 } |
|
333 public delegate IZLibCompressor ZLibCompressorFactory(); |
|
334 public class VNCServerConnection { |
|
335 VNCFramebuffer framebuffer = null; |
|
336 List<Rectangle> dirtyrects = new List<Rectangle>(); |
|
337 int waitingforupdate = 0; |
|
338 Rectangle waitingforupdaterect = Rectangle.Empty; |
|
339 Int32[] SupportedEncodings = new Int32[] { }; |
|
340 MouseButtons mousebuttons = MouseButtons.None; |
|
341 Boolean resized = false; |
|
342 Thread worker = null; |
|
343 Keys modifierKeys = Keys.None; |
|
344 MemoryStream SendBuffer = null; |
|
345 Stream socket; |
|
346 Socket realsocket; |
|
347 Int32 protover; |
|
348 RFBPixelFormat pixelformat; |
|
349 int jpegCounter = 0; |
|
350 Rectangle blurryrect = Rectangle.Empty; |
|
351 int blurryrecoveryline = 0; |
|
352 Point mousePosition = new Point(-1, -1); |
|
353 ZLibCompressorFactory ZLibFactory = null; |
|
354 |
|
355 public int Width { get; private set; } |
|
356 public int Height { get; private set; } |
|
357 public Object Tag { get; set; } |
|
358 |
|
359 public EndPoint RemoteEndPoint { get { return realsocket == null ? null : realsocket.RemoteEndPoint; } } |
|
360 public VNCFramebuffer Framebuffer { |
|
361 get { return framebuffer; } |
|
362 set { |
|
363 if (framebuffer != null) { |
|
364 framebuffer.Update -= FBUpdate; |
|
365 } |
|
366 framebuffer = value; |
|
367 if (value == null) return; |
|
368 lock (dirtyrects) { |
|
369 resized = true; |
|
370 dirtyrects.Clear(); |
|
371 framebuffer.Update += FBUpdate; |
|
372 } |
|
373 FBUpdate(this, new VNCFramebufferUpdateEventArgs(value, new Rectangle(0, 0, framebuffer.Width, framebuffer.Height))); |
|
374 } |
|
375 } |
|
376 |
|
377 public event MouseEventHandler MouseDown; |
|
378 public event MouseEventHandler MouseMove; |
|
379 public event MouseEventHandler MouseUp; |
|
380 public event KeyEventHandler KeyDown; |
|
381 public event KeyEventHandler KeyUp; |
|
382 |
|
383 public event EventHandler Disconnected; |
|
384 |
|
385 public event EventHandler UpdateRequested; |
|
386 public event EventHandler WaitingForUpdate; |
|
387 |
|
388 public event EventHandler<VNCClientAuthenticationEventArgs> ClientAuthentication; |
|
389 public event EventHandler ConnectionComplete; |
|
390 |
|
391 public VNCServerConnection(Socket client) : this(new NetworkStream(client, true), client) { |
|
392 realsocket.SendBufferSize = 1024 * 1024; |
|
393 } |
|
394 public VNCServerConnection(Stream client) : this(client, null) { } |
|
395 public VNCServerConnection(Stream client, Socket socket) { |
|
396 this.socket = client; |
|
397 this.realsocket = socket; |
|
398 pixelformat = new RFBPixelFormat() { |
|
399 BigEndian = false, BitsPerPixel = 32, ColorDepth = 24, TrueColor = true, |
|
400 BlueMax = 255, BlueShift = 0, GreenMax = 255, GreenShift = 8, RedMax = 255, RedShift = 16 |
|
401 }; |
|
402 } |
|
403 |
|
404 public void Close() { |
|
405 socket.Close(); |
|
406 } |
|
407 |
|
408 public void RunAsync(VNCClientConnectedEventArgs args) { |
|
409 worker = new Thread(RunSafe); |
|
410 worker.Start(args); |
|
411 } |
|
412 private void RunSafe(Object state) { |
|
413 try { |
|
414 RunProc((VNCClientConnectedEventArgs)state); |
|
415 } catch (Exception ex) { |
|
416 Console.Error.WriteLine(ex); |
|
417 } finally { |
|
418 try { socket.Close(); } catch (Exception ex) { Console.Error.WriteLine(ex); } |
|
419 if (Disconnected != null) Disconnected(this, new EventArgs()); |
|
420 } |
|
421 } |
|
422 private void RunProc(VNCClientConnectedEventArgs connargs) { |
|
423 Initialisation(connargs); |
|
424 ReceiveLoop(); |
|
425 } |
|
426 |
|
427 private void Initialisation(VNCClientConnectedEventArgs connargs) { |
|
428 { |
|
429 Byte[] protovbuf = Encoding.ASCII.GetBytes("RFB 003.008\n"); |
|
430 SendAll(protovbuf); |
|
431 FlushSendBuffer(); |
|
432 protovbuf = ReceiveAll(12); |
|
433 String protovs = Encoding.ASCII.GetString(protovbuf); |
|
434 protover = int.Parse(protovs.Substring(4, 3)) * 1000 + int.Parse(protovs.Substring(8, 3)); |
|
435 } |
|
436 //Console.WriteLine("Client protocol is {0} = {1}", protovs.TrimEnd('\n'), protover); |
|
437 if (protover < 3003) throw new InvalidOperationException("Unsupported protocol version"); |
|
438 VNCClientAuthenticationEventArgs authargs = new VNCClientAuthenticationEventArgs(this); |
|
439 if (protover >= 3007) { |
|
440 if (connargs.AllowNoAuthentication && connargs.AllowPasswordAuthentication) { |
|
441 SendAll(new Byte[] { 2, 1, 2 }); //2 security types, no security, VNC security |
|
442 } else if (connargs.AllowNoAuthentication) { |
|
443 SendAll(new Byte[] { 1, 1 }); //1 security type, none security |
|
444 } else if (connargs.AllowPasswordAuthentication) { |
|
445 SendAll(new Byte[] { 1, 2 }); //1 security type, VNC security |
|
446 } else { |
|
447 SendAll(new Byte[] { 0 }); //no security types, drop connection |
|
448 throw new InvalidOperationException("No security types allowed"); |
|
449 } |
|
450 FlushSendBuffer(); |
|
451 Byte[] sectype = ReceiveAll(1); |
|
452 if (sectype[0] == 1 && connargs.AllowNoAuthentication) { |
|
453 authargs.UsedPasswordAuthentication = false; |
|
454 } else if (sectype[0] == 2 && connargs.AllowPasswordAuthentication) { |
|
455 authargs.UsedPasswordAuthentication = true; |
|
456 } else throw new InvalidOperationException("Unsupported security type"); |
|
457 } else if (protover == 3003) { |
|
458 if (connargs.AllowNoAuthentication) { |
|
459 SendUInt32(1); //Security type is none |
|
460 authargs.UsedPasswordAuthentication = false; |
|
461 } else if (connargs.AllowPasswordAuthentication) { |
|
462 SendUInt32(2); //Security type is VNC security |
|
463 authargs.UsedPasswordAuthentication = true; |
|
464 } else { |
|
465 SendUInt32(0); //no security types, drop connection |
|
466 throw new InvalidOperationException("No security types allowed"); |
|
467 } |
|
468 FlushSendBuffer(); |
|
469 } else { |
|
470 throw new InvalidOperationException("Unsupported protocol version"); |
|
471 } |
|
472 if (authargs.UsedPasswordAuthentication) { |
|
473 Byte[] challenge = new Byte[16]; |
|
474 (new RNGCryptoServiceProvider()).GetBytes(challenge); |
|
475 SendAll(challenge); |
|
476 FlushSendBuffer(); |
|
477 authargs.VNCAuthChallenge = challenge; |
|
478 authargs.VNCAuthResponse = ReceiveAll(16); |
|
479 } |
|
480 if (ClientAuthentication != null) ClientAuthentication(this, authargs); |
|
481 if (authargs.Drop) { |
|
482 SendUInt32(1); //Security not OK |
|
483 FlushSendBuffer(); |
|
484 throw new Exception("Authentication rejected"); |
|
485 } |
|
486 if (authargs.UsedPasswordAuthentication || protover >= 3008) SendUInt32(0); //Security OK |
|
487 FlushSendBuffer(); |
|
488 Byte[] clientinit = ReceiveAll(1); |
|
489 //Console.WriteLine("Shared = {0}", clientinit[0]); |
|
490 { |
|
491 VNCFramebuffer fb = framebuffer; |
|
492 if (fb != null) { |
|
493 Width = fb.Width; |
|
494 Height = fb.Height; |
|
495 } else { |
|
496 Width = 1024; |
|
497 Height = 768; |
|
498 } |
|
499 } |
|
500 resized = false; |
|
501 SendUInt16((UInt16)Width); |
|
502 SendUInt16((UInt16)Height); |
|
503 SendPixelFormat(pixelformat); |
|
504 { |
|
505 Byte[] desknamestr; |
|
506 if (authargs.DesktopName == null) desknamestr = new Byte[0]; |
|
507 else desknamestr = Encoding.ASCII.GetBytes(authargs.DesktopName); |
|
508 SendUInt32((UInt32)desknamestr.Length); |
|
509 SendAll(desknamestr); |
|
510 } |
|
511 FlushSendBuffer(); |
|
512 if (ConnectionComplete != null) ConnectionComplete(this, new EventArgs()); |
|
513 } |
|
514 |
|
515 private void ReceiveLoop() { |
|
516 while (true) { |
|
517 Byte mtype = ReceiveByte(); |
|
518 switch (mtype) { |
|
519 case 0: //SetPixelFormat |
|
520 ReceiveMessageSetPixelFormat(); |
|
521 break; |
|
522 case 2: //SetEncodings |
|
523 Byte[] b = ReceiveAll(3); |
|
524 b = ReceiveAll(4 * ((b[1] << 8) | b[2])); |
|
525 SupportedEncodings = new Int32[b.Length / 4]; |
|
526 for (int i = 0; i < b.Length; i += 4) SupportedEncodings[i / 4] = (b[i] << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]; |
|
527 break; |
|
528 case 3: //FramebufferUpdateRequest |
|
529 b = ReceiveAll(9); |
|
530 Rectangle r = new Rectangle((b[1] << 8) | b[2], (b[3] << 8) | b[4], (b[5] << 8) | b[6], (b[7] << 8) | b[8]); |
|
531 SendQueuedRectangles(r, b[0] != 0); |
|
532 break; |
|
533 case 4: //KeyEvent |
|
534 ReceiveMessageKeyboard(); |
|
535 break; |
|
536 case 5: //PointerEvent |
|
537 ReceiveMessageMouse(); |
|
538 break; |
|
539 case 6: //ClientCutText |
|
540 b = ReceiveAll(7); |
|
541 ReceiveAll((b[3] << 24) | (b[4] << 16) | (b[5] << 8) | b[6]); |
|
542 break; |
|
543 default: |
|
544 throw new InvalidOperationException("Received unknown message type, synchronization is lost"); |
|
545 } |
|
546 } |
|
547 } |
|
548 private void ReceiveMessageSetPixelFormat() { |
|
549 Byte[] b = ReceiveAll(3); |
|
550 pixelformat = ReceivePixelFormat(); |
|
551 if (!pixelformat.TrueColor) { |
|
552 //I don't want to use a pallette, so I cheat by sending a 8bpp "true color" pallette |
|
553 pixelformat.TrueColor = true; |
|
554 pixelformat.BigEndian = false; |
|
555 pixelformat.RedShift = 0; |
|
556 pixelformat.RedMax = 3; |
|
557 pixelformat.GreenShift = 2; |
|
558 pixelformat.GreenMax = 7; |
|
559 pixelformat.BlueShift = 5; |
|
560 pixelformat.BlueMax = 7; |
|
561 lock (socket) { |
|
562 SendUInt8(1); //SetColourMapEntries |
|
563 SendUInt8(0); //Padding |
|
564 SendUInt16(0); //First colour |
|
565 SendUInt16(256); //Number of colours |
|
566 for (UInt16 blue = 0; blue < 256; blue += 32) { |
|
567 for (UInt16 green = 0; green < 256; green += 32) { |
|
568 for (UInt16 red = 0; red < 256; red += 64) { |
|
569 SendUInt16((UInt16)(red << 8)); |
|
570 SendUInt16((UInt16)(green << 8)); |
|
571 SendUInt16((UInt16)(blue << 8)); |
|
572 } |
|
573 } |
|
574 } |
|
575 FlushSendBuffer(); |
|
576 } |
|
577 } |
|
578 } |
|
579 private void ReceiveMessageKeyboard() { |
|
580 Byte[] b = ReceiveAll(7); |
|
581 Boolean down = b[0] != 0; |
|
582 uint key = (uint)((b[3] << 24) | (b[4] << 16) | (b[5] << 8) | b[6]); |
|
583 //Console.WriteLine("KeyEvent code=0x{0:x} down={1}", key, down); |
|
584 Keys keyval = Keys.None; |
|
585 //see: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h |
|
586 if (key >= 'A' && key <= 'Z') keyval = (Keys)(key + (int)Keys.A - 'A') | Keys.Shift; |
|
587 else if (key >= 'a' && key <= 'z') keyval = (Keys)(key + (int)Keys.A - 'a'); |
|
588 else if (key >= '0' && key <= '9') keyval = (Keys)(key + (int)Keys.D0 - '0'); |
|
589 else if (key >= 0xffb0 && key <= 0xffb9) keyval = (Keys)(key + (int)Keys.NumPad0 - 0xffb0); |
|
590 else if (key >= 0xffbe && key <= 0xffd5) keyval = (Keys)(key + (int)Keys.F1 - 0xffbe); //all the way to F35... |
|
591 else switch (key) { |
|
592 case 0xff08: keyval = Keys.Back; break; |
|
593 case 0xff09: keyval = Keys.Tab; break; |
|
594 case 0xff0a: keyval = Keys.LineFeed; break; |
|
595 case 0xff0b: keyval = Keys.Clear; break; |
|
596 case 0xff0d: keyval = Keys.Return; break; |
|
597 case 0xff13: keyval = Keys.Pause; break; |
|
598 case 0xff14: keyval = Keys.Scroll; break; |
|
599 case 0xff15: keyval = Keys.None; break; //Sys req |
|
600 case 0xff1b: keyval = Keys.Escape; break; |
|
601 case 0xffff: keyval = Keys.Delete; break; |
|
602 case 0xff50: keyval = Keys.Home; break; |
|
603 case 0xff51: keyval = Keys.Left; break; |
|
604 case 0xff52: keyval = Keys.Up; break; |
|
605 case 0xff53: keyval = Keys.Right; break; |
|
606 case 0xff54: keyval = Keys.Down; break; |
|
607 case 0xff55: keyval = Keys.PageUp; break; |
|
608 case 0xff56: keyval = Keys.PageDown; break; |
|
609 case 0xff57: keyval = Keys.End; break; |
|
610 case 0xff58: keyval = Keys.Home; break; |
|
611 case 0xff60: keyval = Keys.Select; break; |
|
612 case 0xff61: keyval = Keys.Print; break; |
|
613 case 0xff62: keyval = Keys.Execute; break; |
|
614 case 0xff63: keyval = Keys.Insert; break; |
|
615 case 0xff65: keyval = Keys.None; break; //Undo |
|
616 case 0xff66: keyval = Keys.None; break; //Redo |
|
617 case 0xff67: keyval = Keys.Apps; break; |
|
618 case 0xff68: keyval = Keys.BrowserSearch; break; |
|
619 case 0xff69: keyval = Keys.Cancel; break; |
|
620 case 0xff6a: keyval = Keys.Help; break; |
|
621 case 0xff6b: keyval = Keys.Pause; break; |
|
622 case 0xff7e: keyval = Keys.None; break; //Character set switch |
|
623 case 0xff7f: keyval = Keys.NumLock; break; |
|
624 case 0xff80: keyval = Keys.Space; break; |
|
625 case 0xff89: keyval = Keys.Tab; break; |
|
626 case 0xff8d: keyval = Keys.Enter; break; |
|
627 case 0xff91: keyval = Keys.F1; break; |
|
628 case 0xff92: keyval = Keys.F2; break; |
|
629 case 0xff93: keyval = Keys.F3; break; |
|
630 case 0xff94: keyval = Keys.F4; break; |
|
631 case 0xff95: keyval = Keys.Home; break; |
|
632 case 0xff96: keyval = Keys.Left; break; |
|
633 case 0xff97: keyval = Keys.Up; break; |
|
634 case 0xff98: keyval = Keys.Right; break; |
|
635 case 0xff99: keyval = Keys.Down; break; |
|
636 case 0xff9a: keyval = Keys.PageUp; break; |
|
637 case 0xff9b: keyval = Keys.PageDown; break; |
|
638 case 0xff9c: keyval = Keys.End; break; |
|
639 case 0xff9d: keyval = Keys.Home; break; |
|
640 case 0xff9e: keyval = Keys.Insert; break; |
|
641 case 0xff9f: keyval = Keys.Delete; break; |
|
642 case 0xffbd: keyval = Keys.None; break; //keypad equals |
|
643 case 0xffaa: keyval = Keys.Multiply; break; |
|
644 case 0xffab: keyval = Keys.Add; break; |
|
645 case 0xffac: keyval = Keys.Separator; break; |
|
646 case 0xffad: keyval = Keys.Subtract; break; |
|
647 case 0xffae: keyval = Keys.Decimal; break; |
|
648 case 0xffaf: keyval = Keys.Divide; break; |
|
649 case 0xffe1: keyval = Keys.LShiftKey; break; |
|
650 case 0xffe2: keyval = Keys.RShiftKey; break; |
|
651 case 0xffe3: keyval = Keys.LControlKey; break; |
|
652 case 0xffe4: keyval = Keys.RControlKey; break; |
|
653 case 0xffe5: keyval = Keys.CapsLock; break; |
|
654 case 0xffe6: keyval = Keys.CapsLock; break; //shift lock!? |
|
655 case 0xffe7: keyval = Keys.None; break; //Left meta!? |
|
656 case 0xffe8: keyval = Keys.None; break; //Right meta!? |
|
657 case 0xffe9: keyval = Keys.LMenu; break; |
|
658 case 0xffea: keyval = Keys.Menu; break; //right alt |
|
659 case 0xffeb: keyval = Keys.LWin; break; |
|
660 case 0xffec: keyval = Keys.RWin; break; |
|
661 case 0xffed: keyval = Keys.None; break; //Left hyper |
|
662 case 0xffee: keyval = Keys.None; break; //Right hyper |
|
663 //Some X11 specific stuff |
|
664 case 0x20: keyval = Keys.Space; break; |
|
665 case 0x21: keyval = Keys.D1 | Keys.Shift; break; //! |
|
666 case 0x22: keyval = Keys.OemQuotes | Keys.Shift; break; //double quotes |
|
667 case 0x23: keyval = Keys.D3 | Keys.Shift; break; //number sign? # |
|
668 case 0x24: keyval = Keys.D4 | Keys.Shift; break; //dollar |
|
669 case 0x25: keyval = Keys.D5 | Keys.Shift; break; //percent |
|
670 case 0x26: keyval = Keys.D7 | Keys.Shift; break; //ampersand |
|
671 case 0x27: keyval = Keys.OemQuotes; break; //apostrophe |
|
672 case 0x28: keyval = Keys.D9 | Keys.Shift; break; //parenleft |
|
673 case 0x29: keyval = Keys.D0 | Keys.Shift; break; //parenright |
|
674 case 0x2a: keyval = Keys.D8 | Keys.Shift; break; //askerisk |
|
675 case 0x2b: keyval = Keys.Oemplus | Keys.Shift; break; //plus |
|
676 case 0x2c: keyval = Keys.Oemcomma; break; //comma |
|
677 case 0x2d: keyval = Keys.OemMinus; break; //minus |
|
678 case 0x2e: keyval = Keys.OemPeriod; break; //period |
|
679 case 0x2f: keyval = Keys.OemQuestion; break; //slash |
|
680 //digits handled above |
|
681 case 0x3a: keyval = Keys.OemSemicolon | Keys.Shift; break; //colon |
|
682 case 0x3b: keyval = Keys.OemSemicolon; break; //semicolon |
|
683 case 0x3c: keyval = Keys.Oemcomma | Keys.Shift; break; //less than |
|
684 case 0x3d: keyval = Keys.Oemplus; break; //equals |
|
685 case 0x3e: keyval = Keys.OemPeriod | Keys.Shift; break; //greater than |
|
686 case 0x3f: keyval = Keys.OemQuestion | Keys.Shift; break; //question mark |
|
687 case 0x40: keyval = Keys.D2 | Keys.Shift; break; //commercial at |
|
688 //capital letters handled above |
|
689 case 0x5b: keyval = Keys.OemOpenBrackets; break; //left square bracker |
|
690 case 0x5c: keyval = Keys.OemBackslash; break; //backslash |
|
691 case 0x5d: keyval = Keys.OemCloseBrackets; break; //right square bracker |
|
692 case 0x5e: keyval = Keys.D6 | Keys.Shift; break; //CIRCUMFLEX ACCENT |
|
693 case 0x5f: keyval = Keys.OemMinus | Keys.Shift; break; //underscore |
|
694 case 0x60: keyval = Keys.Oemtilde; break; //grave accent |
|
695 //small letters handled above |
|
696 case 0x7b: keyval = Keys.OemOpenBrackets | Keys.Shift; break; //left curly bracket |
|
697 case 0x7c: keyval = Keys.OemBackslash | Keys.Shift; break; //vertical line |
|
698 case 0x7d: keyval = Keys.OemCloseBrackets | Keys.Shift; break; //right curly bracket |
|
699 case 0x7e: keyval = Keys.Oemtilde | Keys.Shift; break; //tilde |
|
700 //blah blah |
|
701 //experimental: |
|
702 case 0xfe03: keyval = Keys.RMenu; break; //Alt gr or XK_ISO_Level3_Shift |
|
703 } |
|
704 switch (keyval) { |
|
705 case Keys.LShiftKey: |
|
706 case Keys.RShiftKey: |
|
707 case Keys.ShiftKey: |
|
708 if (down) modifierKeys |= Keys.Shift; else modifierKeys &= ~Keys.Shift; |
|
709 break; |
|
710 case Keys.LControlKey: |
|
711 case Keys.RControlKey: |
|
712 case Keys.ControlKey: |
|
713 if (down) modifierKeys |= Keys.Control; else modifierKeys &= ~Keys.Control; |
|
714 break; |
|
715 case Keys.LMenu: |
|
716 case Keys.RMenu: |
|
717 case Keys.Menu: |
|
718 if (down) modifierKeys |= Keys.Alt; else modifierKeys &= ~Keys.Alt; |
|
719 break; |
|
720 } |
|
721 keyval |= modifierKeys; |
|
722 if (down && KeyDown != null) KeyDown(this, new KeyEventArgs(keyval)); |
|
723 else if (!down && KeyUp != null) KeyUp(this, new KeyEventArgs(keyval)); |
|
724 } |
|
725 private void ReceiveMessageMouse() { |
|
726 Byte[] b = ReceiveAll(5); |
|
727 Point p = new Point((b[1] << 8) | b[2], (b[3] << 8) | b[4]); |
|
728 MouseButtons mb = MouseButtons.None; |
|
729 if ((b[0] & 1) != 0) mb |= MouseButtons.Left; |
|
730 if ((b[0] & 2) != 0) mb |= MouseButtons.Middle; |
|
731 if ((b[0] & 4) != 0) mb |= MouseButtons.Right; |
|
732 if ((b[0] & 32) != 0) mb |= MouseButtons.XButton1; |
|
733 if ((b[0] & 64) != 0) mb |= MouseButtons.XButton2; |
|
734 int dd = 0; |
|
735 if ((b[0] & 8) != 0) dd = 120; |
|
736 if ((b[0] & 16) != 0) dd = -120; |
|
737 //Console.WriteLine("PointerEvent x={0} y={1} buttons={2} delta={3}", p.X, p.Y, mb, dd); |
|
738 foreach (MouseButtons mbi in Enum.GetValues(typeof(MouseButtons))) if ((mousebuttons & mbi) != 0 && (mb & mbi) == 0) if (MouseUp != null) MouseUp(this, new MouseEventArgs(mbi, 0, p.X, p.Y, 0)); |
|
739 if ((dd != 0 || mousePosition != p) && MouseMove != null) MouseMove(this, new MouseEventArgs(mb & mousebuttons, 0, p.X, p.Y, dd)); |
|
740 foreach (MouseButtons mbi in Enum.GetValues(typeof(MouseButtons))) if ((mousebuttons & mbi) == 0 && (mb & mbi) != 0) if (MouseDown != null) MouseDown(this, new MouseEventArgs(mbi, 0, p.X, p.Y, 0)); |
|
741 mousePosition = p; |
|
742 mousebuttons = mb; |
|
743 } |
|
744 |
|
745 private void FBUpdate(Object sender, VNCFramebufferUpdateEventArgs e) { |
|
746 if (e.Framebuffer != framebuffer) return; |
|
747 Rectangle r = e.Area; |
|
748 r.Intersect(new Rectangle(0, 0, e.Framebuffer.Width, e.Framebuffer.Height)); |
|
749 if (r.Width == 0 || r.Height == 0) return; |
|
750 Boolean send; |
|
751 lock (dirtyrects) { |
|
752 for (int i = 0; i < dirtyrects.Count; i++) { |
|
753 Rectangle r2 = dirtyrects[i]; |
|
754 if (r.IntersectsWith(r2)) { |
|
755 dirtyrects.RemoveAt(i); |
|
756 i = -1; |
|
757 r = Rectangle.Union(r, r2); |
|
758 } |
|
759 } |
|
760 dirtyrects.Add(r); |
|
761 send = waitingforupdate > 0; |
|
762 } |
|
763 if (send) { |
|
764 Interlocked.Decrement(ref waitingforupdate); |
|
765 SendQueuedRectangles(waitingforupdaterect, false); |
|
766 } |
|
767 } |
|
768 |
|
769 private void ClearIntersectingQueuedRectangles(Rectangle r) { |
|
770 lock (dirtyrects) { |
|
771 for (int i = 0; i < dirtyrects.Count; i++) { |
|
772 Rectangle r2 = dirtyrects[i]; |
|
773 if (!r2.IntersectsWith(r)) continue; |
|
774 dirtyrects.RemoveAt(i); |
|
775 i--; |
|
776 } |
|
777 dirtyrects.TrimExcess(); |
|
778 } |
|
779 } |
|
780 private void SendQueuedRectangles(Rectangle r, Boolean incremental) { |
|
781 lock (socket) { |
|
782 if (resized) { |
|
783 resized = false; |
|
784 jpegCounter = 0; |
|
785 VNCFramebuffer fb = framebuffer; |
|
786 SendUInt8(0); //FramebufferUpdate |
|
787 SendUInt8(0); //Padding |
|
788 if (Array.IndexOf(SupportedEncodings, -223) == -1) { |
|
789 Console.Error.WriteLine("VNC: Desktop size update not supported"); |
|
790 SendUInt16(fb == null ? (UInt16)1 : (UInt16)2); //Number of rectangles |
|
791 int[] empty = new int[r.Width * r.Height]; |
|
792 SendFBRectangle(empty, new Rectangle(0, 0, r.Width, r.Height), r.Width); |
|
793 ClearIntersectingQueuedRectangles(r); |
|
794 blurryrect = Rectangle.Empty; |
|
795 if (fb != null) SendFBRectangle(fb.Framebuffer, r, fb.Width); |
|
796 } else { |
|
797 if (fb != null) { |
|
798 Width = fb.Width; |
|
799 Height = fb.Height; |
|
800 } |
|
801 Console.Error.WriteLine("VNC: Sending desktop size update {0}x{1}", Width, Height); |
|
802 SendUInt16(1); //Number of rectangles |
|
803 SendUInt16(0); |
|
804 SendUInt16(0); |
|
805 SendUInt16((UInt16)Width); |
|
806 SendUInt16((UInt16)Height); |
|
807 SendUInt32(unchecked((UInt32)(-223))); //Encoding type |
|
808 } |
|
809 FlushSendBuffer(); |
|
810 } else { |
|
811 if (UpdateRequested != null) UpdateRequested(this, new EventArgs()); |
|
812 VNCFramebuffer fb = framebuffer; |
|
813 if (!incremental) { |
|
814 jpegCounter = 0; |
|
815 ClearIntersectingQueuedRectangles(r); |
|
816 blurryrect = Rectangle.Empty; |
|
817 SendUInt8(0); //FramebufferUpdate |
|
818 SendUInt8(0); //Padding |
|
819 SendUInt16(1); //Number of rectangles |
|
820 SendFBRectangle(fb.Framebuffer, r, fb.Width); |
|
821 } else { //incremental |
|
822 List<Rectangle> sending = new List<Rectangle>(); |
|
823 lock (dirtyrects) { |
|
824 if (dirtyrects.Count == 0) { |
|
825 if (jpegCounter > 0) jpegCounter--; |
|
826 } else { |
|
827 if (jpegCounter < 10) jpegCounter++; |
|
828 } |
|
829 for (int i = 0; i < dirtyrects.Count; i++) { |
|
830 Rectangle r2 = dirtyrects[i]; |
|
831 if (!r2.IntersectsWith(r)) continue; |
|
832 dirtyrects.RemoveAt(i); |
|
833 i--; |
|
834 r2.Intersect(r); |
|
835 sending.Add(r2); |
|
836 } |
|
837 dirtyrects.TrimExcess(); |
|
838 if (sending.Count == 0 && blurryrect.IsEmpty) { |
|
839 Interlocked.Increment(ref waitingforupdate); |
|
840 waitingforupdaterect = r; |
|
841 } |
|
842 } |
|
843 if (sending.Count > 0 || !blurryrect.IsEmpty) { |
|
844 SendUInt8(0); //FramebufferUpdate |
|
845 SendUInt8(0); //Padding |
|
846 SendUInt16((UInt16)(sending.Count + (blurryrect.IsEmpty ? 0 : 1))); //Number of rectangles |
|
847 if (!blurryrect.IsEmpty) { |
|
848 //The idea here is to use a lossless compression for a small area to "recover" textual/static content from the JPEG artifacts |
|
849 //Only a small area is updated here each time because compressing a full frame takes too much CPU time |
|
850 Rectangle fixrect = blurryrect; |
|
851 if (blurryrecoveryline < fixrect.Top) blurryrecoveryline = fixrect.Top; |
|
852 else if (blurryrecoveryline >= fixrect.Bottom) blurryrecoveryline = fixrect.Top; |
|
853 fixrect.Intersect(new Rectangle(0, blurryrecoveryline, Int16.MaxValue, 10)); |
|
854 if (fixrect.IsEmpty) fixrect = blurryrect; |
|
855 int oldjpeg = jpegCounter; |
|
856 jpegCounter = 0; |
|
857 SendFBRectangle(fb.Framebuffer, Rectangle.Intersect(fixrect, r), fb.Width); |
|
858 jpegCounter = oldjpeg; |
|
859 blurryrecoveryline = fixrect.Bottom; |
|
860 if (fixrect.Top <= blurryrect.Top && fixrect.Bottom >= blurryrect.Top) { |
|
861 blurryrect.Intersect(new Rectangle(0, fixrect.Bottom, Int16.MaxValue, Int16.MaxValue)); |
|
862 } else if (fixrect.Top <= blurryrect.Bottom && fixrect.Bottom >= blurryrect.Bottom) { |
|
863 blurryrect.Intersect(new Rectangle(0, 0, fixrect.Top, Int16.MaxValue)); |
|
864 } |
|
865 if (blurryrect.Height == 0) blurryrect = Rectangle.Empty; |
|
866 } |
|
867 foreach (Rectangle r2 in sending) { |
|
868 SendFBRectangle(fb.Framebuffer, r2, fb.Width); |
|
869 } |
|
870 } else { |
|
871 if (WaitingForUpdate != null) WaitingForUpdate(this, new EventArgs()); |
|
872 } |
|
873 } |
|
874 } |
|
875 FlushSendBuffer(); |
|
876 } |
|
877 } |
|
878 |
|
879 private void SendFBRectangle(Int32[] fb, Rectangle r, Int32 fbwidth) { |
|
880 r.Intersect(new Rectangle(0, 0, fbwidth, fb.Length / fbwidth)); |
|
881 r.Intersect(new Rectangle(0, 0, Width, Height)); |
|
882 Boolean sent = false; |
|
883 foreach (Int32 enc in SupportedEncodings) { |
|
884 switch (enc) { |
|
885 case 0: |
|
886 SendFBRectangleRaw(fb, r, fbwidth); sent = true; break; |
|
887 case 2: |
|
888 if (r.Height < 8) break; |
|
889 SendFBRectangleRRE(fb, r, fbwidth); sent = true; break; |
|
890 case 5: |
|
891 if (r.Width < 16 || r.Height < 16) break; |
|
892 SendFBRectangleHextile(fb, r, fbwidth); sent = true; break; |
|
893 case 6: |
|
894 sent = SendFBRectangleZLib(fb, r, fbwidth); |
|
895 break; |
|
896 case 7: |
|
897 sent = SendFBRectangleTight(fb, r, fbwidth); |
|
898 break; |
|
899 } |
|
900 if (sent) break; |
|
901 } |
|
902 if (!sent) SendFBRectangleRaw(fb, r, fbwidth); |
|
903 } |
|
904 private void SendFBRectangleHeader(Rectangle r, UInt32 encoding) { |
|
905 SendUInt16((UInt16)r.X); |
|
906 SendUInt16((UInt16)r.Y); |
|
907 SendUInt16((UInt16)r.Width); |
|
908 SendUInt16((UInt16)r.Height); |
|
909 SendUInt32(encoding); |
|
910 } |
|
911 IZLibCompressor TightZLib = null; |
|
912 private unsafe Boolean SendFBRectangleTight(Int32[] framebuffer, Rectangle r, Int32 fbwidth) { |
|
913 if (jpegCounter > 3 && r.Width * r.Height > 100 * 100) { |
|
914 SendFBRectangleHeader(r, 7); |
|
915 SendUInt8(0x90); //Jpeg encoding |
|
916 MemoryStream jpeg = new MemoryStream(); |
|
917 if (r.Width > 0 && r.Height > 0) { |
|
918 fixed (int* fbptr = framebuffer) { |
|
919 using (Bitmap bmp = new Bitmap(r.Width, r.Height, fbwidth * 4, PixelFormat.Format32bppRgb, (IntPtr)(fbptr + (r.Top * fbwidth + r.Left)))) { |
|
920 ImageCodecInfo ici = Array.Find(ImageCodecInfo.GetImageEncoders(), delegate(ImageCodecInfo item) { return item.FormatID == ImageFormat.Jpeg.Guid; }); |
|
921 EncoderParameters ep = new EncoderParameters(1); |
|
922 ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 50L); |
|
923 bmp.Save(jpeg, ici, ep); |
|
924 //bmp.Save(jpeg, ImageFormat.Jpeg); |
|
925 } |
|
926 } |
|
927 } |
|
928 jpeg.Seek(0, SeekOrigin.Begin); |
|
929 int length = (int)jpeg.Length; |
|
930 Byte b1 = (Byte)(length & 0x7F); |
|
931 Byte b2 = (Byte)((length >> 7) & 0x7F); |
|
932 Byte b3 = (Byte)((length >> 14) & 0x7F); |
|
933 if (b3 != 0) b2 |= 0x80; |
|
934 if (b2 != 0) b1 |= 0x80; |
|
935 SendUInt8(b1); |
|
936 if (b2 != 0) SendUInt8(b2); |
|
937 if (b3 != 0) SendUInt8(b3); |
|
938 SendAll(jpeg.ToArray()); |
|
939 blurryrect = blurryrect.IsEmpty ? r : Rectangle.Union(blurryrect, r); |
|
940 } else { |
|
941 if (TightZLib == null && ZLibFactory == null) return false; |
|
942 SendFBRectangleHeader(r, 7); |
|
943 SendUInt8(0x00); //Basic encoding, copy filter (raw), zlib stream 0 |
|
944 Byte[] row; |
|
945 int i = 0; |
|
946 if (pixelformat.BitsPerPixel == 32 && pixelformat.ColorDepth == 24) { |
|
947 row = new Byte[r.Width * r.Height * 3]; |
|
948 for (int y = r.Top; y < r.Bottom; y++) { |
|
949 for (int x = r.Left; x < r.Right; x++) { |
|
950 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x]; |
|
951 row[i++] = (Byte)(pixel >> 16); |
|
952 row[i++] = (Byte)(pixel >> 8); |
|
953 row[i++] = (Byte)(pixel >> 0); |
|
954 } |
|
955 } |
|
956 } else { |
|
957 row = new Byte[r.Width * r.Height * pixelformat.BitsPerPixel / 8]; |
|
958 for (int y = r.Top; y < r.Bottom; y++) { |
|
959 for (int x = r.Left; x < r.Right; x++) { |
|
960 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x]; |
|
961 UInt32 encoded = 0; |
|
962 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift; |
|
963 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift; |
|
964 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift; |
|
965 if (pixelformat.BigEndian) { |
|
966 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b); |
|
967 } else { |
|
968 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b); |
|
969 } |
|
970 } |
|
971 } |
|
972 } |
|
973 if (i >= 12) { |
|
974 if (TightZLib == null) TightZLib = ZLibFactory(); |
|
975 Byte[] compressed = TightZLib.Compress(row, 0, i); |
|
976 int length = compressed.Length; |
|
977 Byte b1 = (Byte)(length & 0x7F); |
|
978 Byte b2 = (Byte)((length >> 7) & 0x7F); |
|
979 Byte b3 = (Byte)((length >> 14) & 0x7F); |
|
980 if (b3 != 0) b2 |= 0x80; |
|
981 if (b2 != 0) b1 |= 0x80; |
|
982 SendUInt8(b1); |
|
983 if (b2 != 0) SendUInt8(b2); |
|
984 if (b3 != 0) SendUInt8(b3); |
|
985 SendAll(compressed); |
|
986 } else { |
|
987 SendAll(row, 0, i); |
|
988 } |
|
989 } |
|
990 return true; |
|
991 } |
|
992 private void SendFBRectangleRaw(Int32[] framebuffer, Rectangle r, int fbwidth) { |
|
993 SendFBRectangleHeader(r, 0); |
|
994 for (int y = r.Top; y < r.Bottom; y++) { |
|
995 Byte[] row = new Byte[r.Width * pixelformat.BitsPerPixel / 8]; |
|
996 int i = 0; |
|
997 for (int x = r.Left; x < r.Right; x++) { |
|
998 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x]; |
|
999 UInt32 encoded = 0; |
|
1000 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift; |
|
1001 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift; |
|
1002 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift; |
|
1003 if (pixelformat.BigEndian) { |
|
1004 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b); |
|
1005 } else { |
|
1006 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b); |
|
1007 } |
|
1008 } |
|
1009 SendAll(row); |
|
1010 } |
|
1011 } |
|
1012 |
|
1013 IZLibCompressor ZLibStream = null; |
|
1014 private Boolean SendFBRectangleZLib(Int32[] framebuffer, Rectangle r, int fbwidth) { |
|
1015 if (ZLibStream == null && ZLibFactory == null) return false; |
|
1016 SendFBRectangleHeader(r, 6); |
|
1017 Byte[] row = new Byte[r.Width * r.Height * pixelformat.BitsPerPixel / 8]; |
|
1018 int i = 0; |
|
1019 for (int y = r.Top; y < r.Bottom; y++) { |
|
1020 for (int x = r.Left; x < r.Right; x++) { |
|
1021 UInt32 pixel = (UInt32)framebuffer[y * fbwidth + x]; |
|
1022 UInt32 encoded = 0; |
|
1023 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift; |
|
1024 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift; |
|
1025 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift; |
|
1026 if (pixelformat.BigEndian) { |
|
1027 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b); |
|
1028 } else { |
|
1029 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b); |
|
1030 } |
|
1031 } |
|
1032 } |
|
1033 if (ZLibStream == null) ZLibStream = ZLibFactory(); |
|
1034 Byte[] compressed = ZLibStream.Compress(row, 0, i); |
|
1035 SendUInt32((UInt32)compressed.Length); |
|
1036 SendAll(compressed); |
|
1037 return true; |
|
1038 } |
|
1039 |
|
1040 |
|
1041 private void SendFBRectangleRRE(Int32[] framebuffer, Rectangle r, int fbwidth) { |
|
1042 SendFBRectangleHeader(r, 2); |
|
1043 int basecolor = framebuffer[r.Y * fbwidth + r.X]; |
|
1044 List<Rectangle> subrects = new List<Rectangle>(); |
|
1045 if (false) { |
|
1046 for (int y = r.Top; y < r.Bottom; y++) { |
|
1047 int color = basecolor; |
|
1048 int runstart = r.Left; |
|
1049 int runlength = 0; |
|
1050 for (int x = r.Left; x < r.Right; x++) { |
|
1051 int newcolor = framebuffer[y * fbwidth + x]; |
|
1052 if (color != newcolor) { |
|
1053 if (color != basecolor && runlength > 0) { |
|
1054 Rectangle r2 = new Rectangle(runstart, y, runlength, 1); |
|
1055 if (r2.Y > 0 && framebuffer[(r2.Y - 1) * fbwidth + r2.X] == color) { |
|
1056 Boolean hasadjacent = false; |
|
1057 Rectangle adjacent = r2; |
|
1058 foreach (Rectangle r3 in subrects) { |
|
1059 if (r3.Left == r2.Left && r3.Width == r2.Width && r3.Top + r3.Height == r2.Top) { |
|
1060 adjacent = r3; |
|
1061 hasadjacent = true; |
|
1062 break; |
|
1063 } |
|
1064 } |
|
1065 if (hasadjacent) { |
|
1066 subrects.Remove(adjacent); |
|
1067 r2 = Rectangle.Union(r2, adjacent); |
|
1068 } |
|
1069 } |
|
1070 subrects.Add(r2); |
|
1071 } |
|
1072 runstart = x; |
|
1073 runlength = 0; |
|
1074 color = newcolor; |
|
1075 } |
|
1076 runlength++; |
|
1077 } |
|
1078 if (color != basecolor && runlength > 0) subrects.Add(new Rectangle(runstart, y, runlength, 1)); |
|
1079 } |
|
1080 } else { |
|
1081 Queue<Rectangle> remaining = new Queue<Rectangle>(); |
|
1082 remaining.Enqueue(r); |
|
1083 while (remaining.Count > 0) { |
|
1084 Rectangle r2 = remaining.Dequeue(); |
|
1085 int color = framebuffer[r2.Y * fbwidth + r2.X]; |
|
1086 int rw = -1, rh = -1; |
|
1087 for (int x = r2.Left; x < r2.Right && rw == -1; x++) { |
|
1088 if (color != framebuffer[r2.Y * fbwidth + x]) rw = x - r2.Left; |
|
1089 } |
|
1090 if (rw == -1) rw = r2.Width; |
|
1091 for (int y = r2.Top + 1; y < r2.Bottom && rh == -1; y++) { |
|
1092 Boolean success = true; |
|
1093 for (int x = r2.Left; x < r2.Left + rw && success; x++) { |
|
1094 if (color != framebuffer[y * fbwidth + x]) success = false; |
|
1095 } |
|
1096 if (!success) rh = y - r2.Top; |
|
1097 } |
|
1098 if (rh == -1) rh = r2.Height; |
|
1099 if (rw != 0 && rh != 0) subrects.Add(new Rectangle(r2.X, r2.Y, rw, rh)); |
|
1100 //if (r2.Width - rw > 0 && rh != 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y, r2.Width - rw, rh)); |
|
1101 if (r2.Height - rh > 0 && rw != 0) remaining.Enqueue(new Rectangle(r2.X, r2.Y + rh, rw, r2.Height - rh)); |
|
1102 //if (r2.Width - rw > 0 && r2.Height - rh > 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y + rh, r2.Width - rw, r2.Height - rh)); |
|
1103 //if (r2.Height - rh > 0) remaining.Enqueue(new Rectangle(r2.X, r2.Y + rh, r2.Width, r2.Height - rh)); |
|
1104 if (r2.Width - rw > 0) remaining.Enqueue(new Rectangle(r2.X + rw, r2.Y, r2.Width - rw, r2.Height)); |
|
1105 } |
|
1106 } |
|
1107 SendUInt32((UInt32)subrects.Count); |
|
1108 SendPixel(basecolor); |
|
1109 foreach (Rectangle r2 in subrects) { |
|
1110 SendPixel(framebuffer[r2.Y * fbwidth + r2.X]); |
|
1111 SendUInt16((UInt16)(r2.Left - r.Left)); |
|
1112 SendUInt16((UInt16)(r2.Top - r.Top)); |
|
1113 SendUInt16((UInt16)r2.Width); |
|
1114 SendUInt16((UInt16)r2.Height); |
|
1115 } |
|
1116 } |
|
1117 private void SendFBRectangleHextile(Int32[] framebuffer, Rectangle r, int fbwidth) { |
|
1118 SendFBRectangleHeader(r, 5); |
|
1119 const int hextileRaw = 1; |
|
1120 const int hextileBgSpecified = 2; |
|
1121 const int hextileFgSpecified = 4; |
|
1122 const int hextileAnySubrects = 8; |
|
1123 const int hextileSubrectsColoured = 16; |
|
1124 int oldBg = 0, oldFg = 0; |
|
1125 bool oldBgValid = false; |
|
1126 bool oldFgValid = false; |
|
1127 Rectangle t = new Rectangle(); |
|
1128 for (t.Y = r.Top; t.Top < r.Bottom; t.Y += 16) { |
|
1129 t.Height = Math.Min(r.Bottom, t.Top + 16) - t.Top; |
|
1130 for (t.X = r.Left; t.Left < r.Right; t.X += 16) { |
|
1131 t.Width = Math.Min(r.Right, t.Left + 16) - t.Left; |
|
1132 int tileType = 0; |
|
1133 int bg = framebuffer[t.Y * fbwidth + t.X]; |
|
1134 int fg = 0; |
|
1135 if (!oldBgValid || oldBg != bg) { |
|
1136 tileType |= hextileBgSpecified; |
|
1137 oldBg = bg; |
|
1138 oldBgValid = true; |
|
1139 } |
|
1140 Boolean foundfg = false; |
|
1141 Boolean foundcol = false; |
|
1142 int subrects = 0; |
|
1143 for (int y = t.Top; y < t.Bottom; y++) { |
|
1144 int color = bg; |
|
1145 int length = 0; |
|
1146 for (int x = t.Left; x < t.Right; x++) { |
|
1147 int pixel = framebuffer[y * fbwidth + x]; |
|
1148 if (pixel == bg) { |
|
1149 } else if (!foundfg) { |
|
1150 fg = pixel; |
|
1151 foundfg = true; |
|
1152 } else if (pixel == fg) { |
|
1153 } else { |
|
1154 foundcol = true; |
|
1155 } |
|
1156 if (color != pixel && length > 0) { |
|
1157 if (color != bg) subrects++; |
|
1158 length = 0; |
|
1159 } |
|
1160 length++; |
|
1161 color = pixel; |
|
1162 } |
|
1163 if (length > 0 && color != bg) subrects++; |
|
1164 } |
|
1165 if (foundcol) { |
|
1166 tileType |= hextileSubrectsColoured | hextileAnySubrects; |
|
1167 oldFgValid = false; |
|
1168 } else if (foundfg) { |
|
1169 tileType |= hextileAnySubrects; |
|
1170 if (!oldFgValid || oldFg != fg) { |
|
1171 tileType |= hextileFgSpecified; |
|
1172 oldFg = fg; |
|
1173 oldFgValid = true; |
|
1174 } |
|
1175 } |
|
1176 int encbytes = 0; |
|
1177 if ((tileType & hextileBgSpecified) != 0) encbytes += pixelformat.BitsPerPixel / 8; |
|
1178 if ((tileType & hextileFgSpecified) != 0) encbytes += pixelformat.BitsPerPixel / 8; |
|
1179 if ((tileType & hextileAnySubrects) != 0) { |
|
1180 int pertile = 2; |
|
1181 if ((tileType & hextileSubrectsColoured) != 0) pertile += pixelformat.BitsPerPixel / 8; |
|
1182 encbytes += pertile * subrects; |
|
1183 } |
|
1184 if (t.Width * t.Height * pixelformat.BitsPerPixel / 8 <= encbytes) { |
|
1185 SendUInt8(hextileRaw); |
|
1186 for (int y = t.Top; y < t.Bottom; y++) for (int x = t.Left; x < t.Right; x++) SendPixel(framebuffer[y * fbwidth + x]); |
|
1187 oldBgValid = oldFgValid = false; |
|
1188 continue; |
|
1189 } |
|
1190 SendUInt8((Byte)tileType); |
|
1191 if ((tileType & hextileBgSpecified) != 0) SendPixel(bg); |
|
1192 if ((tileType & hextileFgSpecified) != 0) SendPixel(fg); |
|
1193 if ((tileType & hextileAnySubrects) != 0) { |
|
1194 SendUInt8((Byte)subrects); |
|
1195 int subrectsa = 0; |
|
1196 for (int y = t.Top; y < t.Bottom; y++) { |
|
1197 int color = bg; |
|
1198 int length = 0; |
|
1199 int start = 0; |
|
1200 for (int x = t.Left; x < t.Right; x++) { |
|
1201 int newcolor = framebuffer[y * fbwidth + x]; |
|
1202 if (color != newcolor && length > 0) { |
|
1203 if (color != bg && subrectsa < subrects) { |
|
1204 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(color); |
|
1205 SendUInt8((Byte)(((start & 0xF) << 4) | ((y - t.Top) & 0xF))); |
|
1206 SendUInt8((Byte)((((length - 1) & 0xF) << 4) | (0 & 0xF))); |
|
1207 subrectsa++; |
|
1208 } |
|
1209 length = 0; |
|
1210 start = x - t.Left; |
|
1211 } |
|
1212 length++; |
|
1213 color = newcolor; |
|
1214 } |
|
1215 if (length > 0 && color != bg && subrectsa < subrects) { |
|
1216 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(color); |
|
1217 SendUInt8((Byte)(((start & 0xF) << 4) | ((y - t.Top) & 0xF))); |
|
1218 SendUInt8((Byte)((((length - 1) & 0xF) << 4) | (0 & 0xF))); |
|
1219 subrectsa++; |
|
1220 } |
|
1221 } |
|
1222 for (int i = subrectsa; i < subrects; i++) { |
|
1223 if ((tileType & hextileSubrectsColoured) != 0) SendPixel(0); |
|
1224 SendUInt16(0); |
|
1225 subrectsa++; |
|
1226 } |
|
1227 if (subrects != subrectsa) throw new Exception("subrects != subrectsa"); |
|
1228 } |
|
1229 } |
|
1230 //Flush(); |
|
1231 } |
|
1232 } |
|
1233 |
|
1234 private void SendPixel(int pixeli) { |
|
1235 UInt32 encoded = 0; |
|
1236 UInt32 pixel = (UInt32)pixeli; |
|
1237 encoded |= ((((pixel >> 16) & 0xff) * (pixelformat.RedMax + 1u) / 256) & pixelformat.RedMax) << pixelformat.RedShift; |
|
1238 encoded |= ((((pixel >> 8) & 0xff) * (pixelformat.GreenMax + 1u) / 256) & pixelformat.GreenMax) << pixelformat.GreenShift; |
|
1239 encoded |= ((((pixel >> 0) & 0xff) * (pixelformat.BlueMax + 1u) / 256) & pixelformat.BlueMax) << pixelformat.BlueShift; |
|
1240 byte[] row = new Byte[pixelformat.BitsPerPixel / 8]; |
|
1241 int i = 0; |
|
1242 if (pixelformat.BigEndian) { |
|
1243 for (int b = pixelformat.BitsPerPixel - 8; b >= 0; b -= 8) row[i++] = (Byte)(encoded >> b); |
|
1244 } else { |
|
1245 for (int b = 0; b < pixelformat.BitsPerPixel; b += 8) row[i++] = (Byte)(encoded >> b); |
|
1246 } |
|
1247 SendAll(row); |
|
1248 } |
|
1249 |
|
1250 private void SendPixelFormat(RFBPixelFormat pf) { |
|
1251 SendUInt8(pf.BitsPerPixel); //bits per pixel |
|
1252 SendUInt8(pf.ColorDepth); //depth |
|
1253 SendUInt8(pf.BigEndian ? (Byte)1 : (Byte)0); //big endian |
|
1254 SendUInt8(pf.TrueColor ? (Byte)1 : (Byte)0); //true color |
|
1255 SendUInt16(pf.RedMax); //red max |
|
1256 SendUInt16(pf.GreenMax); //green max |
|
1257 SendUInt16(pf.BlueMax); //blue max |
|
1258 SendUInt8(pf.RedShift); //red shift |
|
1259 SendUInt8(pf.GreenShift); //green shift |
|
1260 SendUInt8(pf.BlueShift); //blue shift |
|
1261 SendUInt8(0); //padding |
|
1262 SendUInt8(0); //padding |
|
1263 SendUInt8(0); //padding |
|
1264 } |
|
1265 private RFBPixelFormat ReceivePixelFormat() { |
|
1266 Byte[] b = ReceiveAll(16); |
|
1267 RFBPixelFormat pf = new RFBPixelFormat(); |
|
1268 pf.BitsPerPixel = b[0]; |
|
1269 pf.ColorDepth = b[1]; |
|
1270 pf.BigEndian = b[2] != 0; |
|
1271 pf.TrueColor = b[3] != 0; |
|
1272 pf.RedMax = (UInt16)((b[4] << 8) | b[5]); |
|
1273 pf.GreenMax = (UInt16)((b[6] << 8) | b[7]); |
|
1274 pf.BlueMax = (UInt16)((b[8] << 8) | b[9]); |
|
1275 pf.RedShift = b[10]; |
|
1276 pf.GreenShift = b[11]; |
|
1277 pf.BlueShift = b[12]; |
|
1278 return pf; |
|
1279 } |
|
1280 |
|
1281 private void SendUInt32(UInt32 value) { |
|
1282 SendAll(new Byte[] { (Byte)(value >> 24), (Byte)(value >> 16), (Byte)(value >> 8), (Byte)value }); |
|
1283 } |
|
1284 private void SendUInt16(UInt16 value) { |
|
1285 SendAll(new Byte[] { (Byte)(value >> 8), (Byte)value }); |
|
1286 } |
|
1287 private void SendUInt8(Byte value) { |
|
1288 SendAll(new Byte[] { value }); |
|
1289 } |
|
1290 private void SendAll(Byte[] buffer) { |
|
1291 SendAll(buffer, 0, buffer.Length); |
|
1292 } |
|
1293 |
|
1294 private void SendAll(Byte[] buffer, int off, int len) { |
|
1295 if (SendBuffer == null) SendBuffer = new MemoryStream(); |
|
1296 SendBuffer.Write(buffer, off, len); |
|
1297 if (SendBuffer.Length > 102400) FlushSendBuffer(); |
|
1298 } |
|
1299 private void FlushSendBuffer() { |
|
1300 if (SendBuffer == null) return; |
|
1301 SendBuffer.Seek(0, SeekOrigin.Begin); |
|
1302 SendBuffer.WriteTo(socket); |
|
1303 SendBuffer.SetLength(0); |
|
1304 } |
|
1305 |
|
1306 private Byte ReceiveByte() { |
|
1307 Byte[] buffer = new Byte[1]; |
|
1308 ReceiveAll(buffer, 0, 1); |
|
1309 return buffer[0]; |
|
1310 } |
|
1311 private Byte[] ReceiveAll(int len) { |
|
1312 Byte[] buffer = new Byte[len]; |
|
1313 ReceiveAll(buffer, 0, len); |
|
1314 return buffer; |
|
1315 } |
|
1316 private void ReceiveAll(Byte[] buffer, int off, int len) { |
|
1317 while (len > 0) { |
|
1318 int sent = socket.Read(buffer, off, len); |
|
1319 if (sent == 0) throw new EndOfStreamException(); |
|
1320 len -= sent; |
|
1321 off += sent; |
|
1322 } |
|
1323 } |
|
1324 } |
|
1325 } |