CVS: rdesktop pstcache.c,NONE,1.1 Makefile,1.44,1.45 cache.c,1.13,1.14 constants.h,1.34,1.35 orders.c,1.35,1.36 orders.h,1.8,1.9 proto.h,1.64,1.65 rdesktop.c,1.107,1.108 rdp.c,1.64,1.65 types.h,1.19,1.20 xwin.c,1.173,1.174

Jay Sorg <[email protected]>
Newsgroups gmane.network.rdesktop.cvs
Message-ID <[email protected]>
Update of /cvsroot/rdesktop/rdesktop
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4706

Modified Files:
	Makefile cache.c constants.h orders.c orders.h proto.h 
	rdesktop.c rdp.c types.h xwin.c 
Added Files:
	pstcache.c 
Log Message:
added persistant bitmap chaching from Jeroen Meijer, slightly modified

--- NEW FILE: pstcache.c ---
/*
   rdesktop: A Remote Desktop Protocol client.
   Persistent Bitmap Cache routines
   Copyright (C) Jeroen Meijer 2004

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "rdesktop.h"

#define MAX_CELL_SIZE		0x1000			/* pixels */

#define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)

extern int g_server_bpp;
extern uint32 g_stamp;
extern BOOL g_bitmap_cache;
extern BOOL g_bitmap_cache_persist_enable;
extern BOOL g_bitmap_cache_precache;

int g_pstcache_fd[8];
int g_pstcache_Bpp;
BOOL g_pstcache_enumerated = False;
uint8 zero_id[] = {0, 0, 0, 0, 0, 0, 0, 0};


/* Update usage info for a bitmap */
void
pstcache_touch_bitmap(uint8 cache_id, uint16 cache_idx, uint32 stamp)
{
	int fd;

	if (!IS_PERSISTENT(cache_id))
		return;

	fd = g_pstcache_fd[cache_id];
	rd_lseek_file(fd, 12 + cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
	rd_write_file(fd, &stamp, sizeof(stamp));
}

/* Load a bitmap from the persistent cache */
BOOL
pstcache_load_bitmap(uint8 cache_id, uint16 cache_idx)
{
	uint8 *celldata;
	int fd;
	CELLHEADER cellhdr;
	HBITMAP bitmap;

	if (!(g_bitmap_cache_persist_enable && IS_PERSISTENT(cache_id)))
		return False;

	fd = g_pstcache_fd[cache_id];
	rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
	rd_read_file(fd, &cellhdr, sizeof(CELLHEADER));
	celldata = (uint8 *)xmalloc(cellhdr.length);
	rd_read_file(fd, celldata, cellhdr.length);

	DEBUG(("Loading bitmap from disk (%d:%d)\n", cache_id, cache_idx));

	bitmap = ui_create_bitmap(cellhdr.width, cellhdr.height, celldata);
	cache_put_bitmap(cache_id, cache_idx, bitmap, cellhdr.stamp);

	xfree(celldata);
	return True;
}

/* Store a bitmap in the persistent cache */
BOOL
pstcache_put_bitmap(uint8 cache_id, uint16 cache_idx, uint8 *bitmap_id,
		uint16 width, uint16 height, uint16 length, uint8 *data)
{
	int fd;
	CELLHEADER cellhdr;

	if (!IS_PERSISTENT(cache_id))
		return False;

	memcpy(cellhdr.bitmap_id, bitmap_id, sizeof(BITMAP_ID));
	cellhdr.width = width;
	cellhdr.height = height;
	cellhdr.length = length;
	cellhdr.stamp = 0;

	fd = g_pstcache_fd[cache_id];
	rd_lseek_file(fd, cache_idx * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
	rd_write_file(fd, &cellhdr, sizeof(CELLHEADER));
	rd_write_file(fd, data, length);

	return True;
}

/* list the bitmaps from the persistent cache file */
int
pstcache_enumerate(uint8 cache_id, uint8 *idlist)
{
	int fd, n, c = 0;
	CELLHEADER cellhdr;

	if (!(g_bitmap_cache && g_bitmap_cache_persist_enable && IS_PERSISTENT(cache_id)))
		return 0;

	/* The server disconnects if the bitmap cache content is sent more than once */
	if (g_pstcache_enumerated)
		return 0;

	DEBUG(("pstcache enumeration... "));
	for (n = 0; n < BMPCACHE2_NUM_PSTCELLS; n++)
	{
		fd = g_pstcache_fd[cache_id];
		rd_lseek_file(fd, n * (g_pstcache_Bpp * MAX_CELL_SIZE + sizeof(CELLHEADER)));
		if (rd_read_file(fd, &cellhdr, sizeof(CELLHEADER)) <= 0)
			break;

		if (memcmp(cellhdr.bitmap_id, zero_id, sizeof(BITMAP_ID)) != 0)
		{
			memcpy(idlist + n * sizeof(BITMAP_ID), cellhdr.bitmap_id,
					sizeof(BITMAP_ID));

			if (cellhdr.stamp)
			{
				/* Pre-caching is not possible with 8bpp because a colourmap
				 * is needed to load them */
				if (g_bitmap_cache_precache && (g_server_bpp > 8))
				{
					if (pstcache_load_bitmap(cache_id, n))
						c++;
				}

				g_stamp = MAX(g_stamp, cellhdr.stamp);
			}
		}
		else
		{
			break;
		}
	}

	DEBUG(("%d bitmaps in persistent cache, %d bitmaps loaded in memory\n", n, c));
	g_pstcache_enumerated = True;
	return n;
}

/* initialise the persistent bitmap cache */
BOOL
pstcache_init(uint8 cache_id)
{
	int fd;
	char filename[256];

	if (g_pstcache_enumerated)
		return True;

	g_pstcache_fd[cache_id] = 0;

	if (!(g_bitmap_cache && g_bitmap_cache_persist_enable))
		return False;

	if (!rd_pstcache_mkdir())
	{
		DEBUG(("failed to get/make cache directory!\n"));
		return False;
	}

	g_pstcache_Bpp = (g_server_bpp + 7) / 8;
	sprintf(filename, "cache/pstcache_%d_%d", cache_id, g_pstcache_Bpp);
	DEBUG(("persistent bitmap cache file: %s\n", filename));

	fd = rd_open_file(filename);
	if (fd == -1)
		return False;

	if (!rd_lock_file(fd, 0, 0))
	{
		warning("Persistent bitmap caching is disabled. (The file is already in use)\n");
		rd_close_file(fd);
		return False;
	}

	g_pstcache_fd[cache_id] = fd;
	return True;
}

Index: Makefile
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/Makefile,v
retrieving revision 1.44
retrieving revision 1.45
diff -C2 -d -r1.44 -r1.45
*** Makefile	27 Apr 2004 12:55:33 -0000	1.44
--- Makefile	27 Jun 2004 17:51:54 -0000	1.45
***************
*** 16,20 ****
  KEYMAP_PATH = $(datadir)/keymaps/
  
! RDPOBJ   = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o
  X11OBJ   = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
  VNCOBJ   = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o
--- 16,20 ----
  KEYMAP_PATH = $(datadir)/keymaps/
  
! RDPOBJ   = tcp.o iso.o mcs.o secure.o licence.o rdp.o orders.o bitmap.o cache.o rdp5.o channels.o rdpdr.o serial.o printer.o disk.o parallel.o printercache.o mppc.o pstcache.o
  X11OBJ   = rdesktop.o xwin.o xkeymap.o ewmhints.o xclip.o cliprdr.o
  VNCOBJ   = vnc/rdp2vnc.o vnc/vnc.o vnc/xkeymap.o vnc/x11stubs.o

Index: cache.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/cache.c,v
retrieving revision 1.13
retrieving revision 1.14
diff -C2 -d -r1.13 -r1.14
*** cache.c	24 Dec 2003 17:23:03 -0000	1.13
--- cache.c	27 Jun 2004 17:51:54 -0000	1.14
***************
*** 22,29 ****
  
  #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
  
  
  /* BITMAP CACHE */
! static HBITMAP g_bmpcache[3][600];
  
  /* Retrieve a bitmap from the cache */
--- 22,61 ----
  
  #define NUM_ELEMENTS(array) (sizeof(array) / sizeof(array[0]))
+ #define TOUCH(id, idx) (g_bmpcache[id][idx].usage = ++g_stamp)
+ #define IS_PERSISTENT(id) (g_pstcache_fd[id] > 0)
+ 
+ extern int g_pstcache_fd[];
+ 
+ uint32 g_stamp;
+ int g_num_bitmaps_in_memory[3];
  
  
  /* BITMAP CACHE */
! static BMPCACHEENTRY g_bmpcache[3][0xa00];
! 
! /* Remove the least-recently used bitmap from the cache */
! void
! cache_remove_lru_bitmap(uint8 cache_id)
! {
! 	int i;
! 	uint16 cache_idx = 0;
! 	uint32 m = -1;
! 	BMPCACHEENTRY *pbce;
! 
! 	for (i = 0; i < NUM_ELEMENTS(g_bmpcache[cache_id]); i++)
! 	{
! 		if (g_bmpcache[cache_id][i].bitmap && g_bmpcache[cache_id][i].usage < m)
! 		{
! 			cache_idx = i;
! 			m = g_bmpcache[cache_id][i].usage;
! 		}
! 	}
! 
! 	pbce = &g_bmpcache[cache_id][cache_idx];
! 	ui_destroy_bitmap(pbce->bitmap);
! 	--g_num_bitmaps_in_memory[cache_id];
! 	pbce->bitmap = 0;
! 	pbce->usage = 0;
! }
  
  /* Retrieve a bitmap from the cache */
***************
*** 31,41 ****
  cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
  {
! 	HBITMAP bitmap;
  
  	if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
  	{
! 		bitmap = g_bmpcache[cache_id][cache_idx];
! 		if (bitmap != NULL)
! 			return bitmap;
  	}
  
--- 63,78 ----
  cache_get_bitmap(uint8 cache_id, uint16 cache_idx)
  {
! 	HBITMAP *pbitmap;
  
  	if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
  	{
! 		pbitmap = &g_bmpcache[cache_id][cache_idx].bitmap;
! 		if ((*pbitmap != 0) || pstcache_load_bitmap(cache_id, cache_idx))
! 		{
! 			if (IS_PERSISTENT(cache_id))
! 				TOUCH(cache_id, cache_idx);
! 
! 			return *pbitmap;
! 		}
  	}
  
***************
*** 46,50 ****
  /* Store a bitmap in the cache */
  void
! cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap)
  {
  	HBITMAP old;
--- 83,87 ----
  /* Store a bitmap in the cache */
  void
! cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap, uint32 stamp)
  {
  	HBITMAP old;
***************
*** 52,60 ****
  	if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
  	{
! 		old = g_bmpcache[cache_id][cache_idx];
  		if (old != NULL)
  			ui_destroy_bitmap(old);
  
! 		g_bmpcache[cache_id][cache_idx] = bitmap;
  	}
  	else
--- 89,105 ----
  	if ((cache_id < NUM_ELEMENTS(g_bmpcache)) && (cache_idx < NUM_ELEMENTS(g_bmpcache[0])))
  	{
! 		old = g_bmpcache[cache_id][cache_idx].bitmap;
  		if (old != NULL)
+ 		{
  			ui_destroy_bitmap(old);
+ 		}
+ 		else
+ 		{
+ 			if (++g_num_bitmaps_in_memory[cache_id] > BMPCACHE2_C2_CELLS)
+ 				cache_remove_lru_bitmap(cache_id);
+ 		}
  
! 		g_bmpcache[cache_id][cache_idx].bitmap = bitmap;
! 		g_bmpcache[cache_id][cache_idx].usage = stamp;
  	}
  	else
***************
*** 64,67 ****
--- 109,124 ----
  }
  
+ /* Updates the persistent bitmap cache MRU information on exit */
+ void
+ cache_save_state(void)
+ {
+ 	int id, idx;
+ 
+ 	for (id = 0; id < NUM_ELEMENTS(g_bmpcache); id++)
+ 		if (IS_PERSISTENT(id))
+ 			for (idx = 0; idx < NUM_ELEMENTS(g_bmpcache[id]); idx++)
+ 				pstcache_touch_bitmap(id, idx, g_bmpcache[id][idx].usage);
+ }
+ 
  
  /* FONT CACHE */

Index: constants.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/constants.h,v
retrieving revision 1.34
retrieving revision 1.35
diff -C2 -d -r1.34 -r1.35
*** constants.h	27 Apr 2004 12:55:33 -0000	1.34
--- constants.h	27 Jun 2004 17:51:54 -0000	1.35
***************
*** 200,203 ****
--- 200,212 ----
  #define TEXT2_IMPLICIT_X	0x20
  
+ /* RDP bitmap cache (version 2) constants */
+ #define BMPCACHE2_C0_CELLS	0x78
+ #define BMPCACHE2_C1_CELLS	0x78
+ #define BMPCACHE2_C2_CELLS	0x150
+ #define BMPCACHE2_NUM_PSTCELLS	0x9f6
+ 
+ #define PDU_FLAG_FIRST		0x01
+ #define PDU_FLAG_LAST		0x02
+ 
  /* RDP capabilities */
  #define RDP_CAPSET_GENERAL	1	/* Maps to generalCapabilitySet in T.128 page 138 */
***************
*** 232,237 ****
  #define RDP_CAPLEN_COLCACHE	0x08
  
! #define RDP_CAPSET_UNKNOWN	13
! #define RDP_CAPLEN_UNKNOWN	0x9C
  
  #define RDP_SOURCE		"MSTSC"
--- 241,247 ----
  #define RDP_CAPLEN_COLCACHE	0x08
  
! #define RDP_CAPSET_BMPCACHE2	19
! #define RDP_CAPLEN_BMPCACHE2	0x28
! #define BMPCACHE2_FLAG_PERSIST	(1<<31)
  
  #define RDP_SOURCE		"MSTSC"

Index: orders.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/orders.c,v
retrieving revision 1.35
retrieving revision 1.36
diff -C2 -d -r1.35 -r1.36
*** orders.c	27 Apr 2004 12:55:33 -0000	1.35
--- orders.c	27 Jun 2004 17:51:54 -0000	1.36
***************
*** 671,675 ****
  	bitmap = ui_create_bitmap(width, height, inverted);
  	xfree(inverted);
! 	cache_put_bitmap(cache_id, cache_idx, bitmap);
  }
  
--- 671,675 ----
  	bitmap = ui_create_bitmap(width, height, inverted);
  	xfree(inverted);
! 	cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
  }
  
***************
*** 696,700 ****
  	in_uint16_le(s, cache_idx);
  
! 	if (!g_use_rdp5)
  	{
  
--- 696,704 ----
  	in_uint16_le(s, cache_idx);
  
! 	if (g_use_rdp5)
! 	{
! 		size = bufsize;
! 	}
! 	else
  	{
  
***************
*** 707,714 ****
  
  	}
- 	else
- 	{
- 		size = bufsize;
- 	}
  	in_uint8p(s, data, size);
  
--- 711,714 ----
***************
*** 720,724 ****
  	{
  		bitmap = ui_create_bitmap(width, height, bmpdata);
! 		cache_put_bitmap(cache_id, cache_idx, bitmap);
  	}
  	else
--- 720,724 ----
  	{
  		bitmap = ui_create_bitmap(width, height, bmpdata);
! 		cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
  	}
  	else
***************
*** 730,733 ****
--- 730,813 ----
  }
  
+ /* Process a bitmap cache v2 order */
+ static void
+ process_bmpcache2(STREAM s, uint16 flags, BOOL compressed)
+ {
+ 	HBITMAP bitmap;
+ 	int y;
+ 	uint8 cache_id, cache_idx_low, width, height, Bpp;
+ 	uint16 cache_idx, bufsize;
+ 	uint8 *data, *bmpdata, *bitmap_id;
+ 
+ 	bitmap_id = NULL;	/* prevent compiler warning */
+ 	cache_id = flags & ID_MASK;
+ 	Bpp = ((flags & MODE_MASK) >> MODE_SHIFT) - 2;
+ 
+ 	if (flags & PERSIST)
+ 	{
+ 		in_uint8p(s, bitmap_id, 8);
+ 	}
+ 
+ 	if (flags & SQUARE)
+ 	{
+ 		in_uint8(s, width);
+ 		height = width;
+ 	}
+ 	else
+ 	{
+ 		in_uint8(s, width);
+ 		in_uint8(s, height);
+ 	}
+ 
+ 	in_uint16_be(s, bufsize);
+ 	bufsize &= BUFSIZE_MASK;
+ 	in_uint8(s, cache_idx);
+ 
+ 	if (cache_idx & LONG_FORMAT)
+ 	{
+ 		in_uint8(s, cache_idx_low);
+ 		cache_idx = ((cache_idx ^ LONG_FORMAT) << 8) + cache_idx_low;
+ 	}
+ 
+ 	in_uint8p(s, data, bufsize);
+ 
+ 	DEBUG(("BMPCACHE2(compr=%d,flags=%x,cx=%d,cy=%d,id=%d,idx=%d,Bpp=%d,bs=%d)\n",
+ 			compressed, flags, width, height, cache_id, cache_idx, Bpp, bufsize));
+ 
+ 	bmpdata = (uint8 *) xmalloc(width * height * Bpp);
+ 
+ 	if (compressed)
+ 	{
+ 		if (!bitmap_decompress(bmpdata, width, height, data, bufsize, Bpp))
+ 		{
+ 			DEBUG(("Failed to decompress bitmap data\n"));
+ 			xfree(bmpdata);
+ 			return;
+ 		}
+ 	}
+ 	else
+ 	{
+ 		for (y = 0; y < height; y++)
+ 			memcpy(&bmpdata[(height - y - 1) * (width * Bpp)],
+ 					&data[y * (width * Bpp)], width * Bpp);
+ 	}
+ 
+ 	bitmap = ui_create_bitmap(width, height, bmpdata);
+ 
+ 	if (bitmap)
+ 	{
+ 		cache_put_bitmap(cache_id, cache_idx, bitmap, 0);
+ 		if (flags & PERSIST)
+ 			pstcache_put_bitmap(cache_id, cache_idx, bitmap_id, width, height,
+ 					width * height * Bpp, bmpdata);
+ 	}
+ 	else
+ 	{
+ 		DEBUG(("process_bmpcache2: ui_create_bitmap failed\n"));
+ 	}
+ 
+ 	xfree(bmpdata);
+ }
+ 
  /* Process a colourmap cache order */
  static void
***************
*** 797,806 ****
  process_secondary_order(STREAM s)
  {
! 	uint16 length;
  	uint8 type;
  	uint8 *next_order;
  
! 	in_uint16_le(s, length);
! 	in_uint8s(s, 2);	/* flags */
  	in_uint8(s, type);
  
--- 877,890 ----
  process_secondary_order(STREAM s)
  {
! 	/* The length isn't calculated correctly by the server.
! 	 * For very compact orders the length becomes negative
! 	 * so a signed integer must be used. */
! 	sint16 length;
! 	uint16 flags;
  	uint8 type;
  	uint8 *next_order;
  
! 	in_uint16_le(s, (uint16) length);
! 	in_uint16_le(s, flags);		/* used by bmpcache2 */
  	in_uint8(s, type);
  
***************
*** 825,828 ****
--- 909,920 ----
  			break;
  
+ 		case RDP_ORDER_RAW_BMPCACHE2:
+ 			process_bmpcache2(s, flags, False);	/* uncompressed */
+ 			break;
+ 
+ 		case RDP_ORDER_BMPCACHE2:
+ 			process_bmpcache2(s, flags, True);	/* compressed */
+ 			break;
+ 
  		default:
  			unimpl("secondary order %d\n", type);

Index: orders.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/orders.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -C2 -d -r1.8 -r1.9
*** orders.h	16 May 2003 21:55:14 -0000	1.8
--- orders.h	27 Jun 2004 17:51:54 -0000	1.9
***************
*** 47,51 ****
  	RDP_ORDER_COLCACHE = 1,
  	RDP_ORDER_BMPCACHE = 2,
! 	RDP_ORDER_FONTCACHE = 3
  };
  
--- 47,53 ----
  	RDP_ORDER_COLCACHE = 1,
  	RDP_ORDER_BMPCACHE = 2,
! 	RDP_ORDER_FONTCACHE = 3,
! 	RDP_ORDER_RAW_BMPCACHE2 = 4,
! 	RDP_ORDER_BMPCACHE2 = 5
  };
  
***************
*** 253,256 ****
--- 255,270 ----
  RDP_BMPCACHE_ORDER;
  
+ /* RDP_BMPCACHE2_ORDER */
+ #define ID_MASK			0x0007
+ #define MODE_MASK		0x0038
+ #define SQUARE			0x0080
+ #define PERSIST			0x0100
+ #define FLAG_51_UNKNOWN		0x0800
+ 
+ #define MODE_SHIFT		3
+ 
+ #define LONG_FORMAT		0x80
+ #define BUFSIZE_MASK		0x3FFF  /* or 0x1FFF? */
+ 
  #define MAX_GLYPH 32
  

Index: proto.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/proto.h,v
retrieving revision 1.64
retrieving revision 1.65
diff -C2 -d -r1.64 -r1.65
*** proto.h	16 Jun 2004 03:08:54 -0000	1.64
--- proto.h	27 Jun 2004 17:51:54 -0000	1.65
***************
*** 3,7 ****
  /* cache.c */
  HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx);
! void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap);
  FONTGLYPH *cache_get_font(uint8 font, uint16 character);
  void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width,
--- 3,8 ----
  /* cache.c */
  HBITMAP cache_get_bitmap(uint8 cache_id, uint16 cache_idx);
! void cache_put_bitmap(uint8 cache_id, uint16 cache_idx, HBITMAP bitmap, uint32 stamp);
! void cache_save_state(void);
  FONTGLYPH *cache_get_font(uint8 font, uint16 character);
  void cache_put_font(uint8 font, uint16 character, uint16 offset, uint16 baseline, uint16 width,
***************
*** 61,64 ****
--- 62,72 ----
  int printercache_load_blob(char *printer_name, uint8 ** data);
  void printercache_process(STREAM s);
+ /* pstcache.c */
+ void pstcache_touch_bitmap(uint8 id, uint16 idx, uint32 stamp);
+ BOOL pstcache_load_bitmap(uint8 id, uint16 idx);
+ BOOL pstcache_put_bitmap(uint8 id, uint16 idx, uint8 *bmp_id, uint16 wd,
+ 		uint16 ht, uint16 len, uint8 *data);
+ int pstcache_enumerate(uint8 id, uint8 *list);
+ BOOL pstcache_init(uint8 id);
  /* rdesktop.c */
  int main(int argc, char *argv[]);
***************
*** 76,79 ****
--- 84,94 ----
  int load_licence(unsigned char **data);
  void save_licence(unsigned char *data, int length);
+ BOOL rd_pstcache_mkdir(void);
+ int rd_open_file(char *filename);
+ void rd_close_file(int fd);
+ int rd_read_file(int fd, void *ptr, int len);
+ int rd_write_file(int fd, void* ptr, int len);
+ int rd_lseek_file(int fd, int offset);
+ BOOL rd_lock_file(int fd, int start, int len);
  /* rdp5.c */
  void rdp5_process(STREAM s, BOOL encryption);

Index: rdesktop.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/rdesktop.c,v
retrieving revision 1.107
retrieving revision 1.108
diff -C2 -d -r1.107 -r1.108
*** rdesktop.c	15 Jun 2004 22:17:08 -0000	1.107
--- rdesktop.c	27 Jun 2004 17:51:54 -0000	1.108
***************
*** 60,63 ****
--- 60,65 ----
  BOOL g_sendmotion = True;
  BOOL g_bitmap_cache = True;
+ BOOL g_bitmap_cache_persist_enable = False;
+ BOOL g_bitmap_cache_precache = True;
  BOOL g_encryption = True;
  BOOL packet_encryption = True;
***************
*** 125,130 ****
  	fprintf(stderr, "   -X: embed into another window with a given id.\n");
  	fprintf(stderr, "   -a: connection colour depth\n");
! 	fprintf(stderr,
! 		"   -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex number)\n");
  	fprintf(stderr, "   -r: enable specified device redirection (this flag can be repeated)\n");
  	fprintf(stderr,
--- 127,132 ----
  	fprintf(stderr, "   -X: embed into another window with a given id.\n");
  	fprintf(stderr, "   -a: connection colour depth\n");
! 	fprintf(stderr, "   -x: RDP5 experience (m[odem 28.8], b[roadband], l[an] or hex nr.)\n");
! 	fprintf(stderr, "   -P: use persistent bitmap caching\n");
  	fprintf(stderr, "   -r: enable specified device redirection (this flag can be repeated)\n");
  	fprintf(stderr,
***************
*** 365,369 ****
  #endif
  
! 	while ((c = getopt(argc, argv, VNCOPT "u:d:s:c:p:n:k:g:fbBeEmCDKS:T:NX:a:x:r:045h?")) != -1)
  	{
  		switch (c)
--- 367,372 ----
  #endif
  
! 	while ((c = getopt(argc, argv,
! 			VNCOPT "u:d:s:c:p:n:k:g:fbBeEmCDKS:T:NX:a:x:Pr:045h?")) != -1)
  	{
  		switch (c)
***************
*** 548,551 ****
--- 551,558 ----
  				break;
  
+ 			case 'P':
+ 				g_bitmap_cache_persist_enable = True;
+ 				break;
+ 
  			case 'r':
  
***************
*** 714,717 ****
--- 721,725 ----
  
  	DEBUG(("Disconnecting...\n"));
+ 	cache_save_state();
  	rdp_disconnect();
  	ui_deinit();
***************
*** 1122,1123 ****
--- 1130,1223 ----
  	xfree(path);
  }
+ 
+ /* Create the bitmap cache directory */
+ BOOL
+ rd_pstcache_mkdir(void)
+ {
+ 	char *home;
+ 	char bmpcache_dir[256];
+ 
+ 	home = getenv("HOME");
+ 
+ 	if (home == NULL)
+ 		return False;
+ 
+ 	sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop");
+ 
+ 	if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
+ 	{
+ 		perror(bmpcache_dir);
+ 		return False;
+ 	}
+ 
+ 	sprintf(bmpcache_dir, "%s/%s", home, ".rdesktop/cache");
+ 
+ 	if ((mkdir(bmpcache_dir, S_IRWXU) == -1) && errno != EEXIST)
+ 	{
+ 		perror(bmpcache_dir);
+ 		return False;
+ 	}
+ 
+ 	return True;
+ }
+ 
+ /* open a file in the .rdesktop directory */
+ int
+ rd_open_file(char *filename)
+ {
+ 	char *home;
+ 	char fn[256];
+    int fd;
+ 
+ 	home = getenv("HOME");
+ 	if (home == NULL)
+ 		return -1;
+ 	sprintf(fn, "%s/.rdesktop/%s", home, filename);
+ 	fd = open(fn, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
+ 	if (fd == -1)
+ 		perror(fn);
+ 	return fd;
+ }
+ 
+ /* close file */
+ void
+ rd_close_file(int fd)
+ {
+   close(fd);
+ }
+ 
+ /* read from file*/
+ int
+ rd_read_file(int fd, void *ptr, int len)
+ {
+   return read(fd, ptr, len);
+ }
+ 
+ /* write to file */
+ int
+ rd_write_file(int fd, void* ptr, int len)
+ {
+   return write(fd, ptr, len);
+ }
+ 
+ /* move file pointer */
+ int
+ rd_lseek_file(int fd, int offset)
+ {
+   return lseek(fd, offset, SEEK_SET);
+ }
+ 
+ /* do a write lock on a file */
+ BOOL
+ rd_lock_file(int fd, int start, int len)
+ {
+ 	struct flock lock;
+ 
+ 	lock.l_type = F_WRLCK;
+ 	lock.l_whence = SEEK_SET;
+ 	lock.l_start = start;
+ 	lock.l_len = len;
+ 	if (fcntl(fd, F_SETLK, &lock) == -1)
+ 		return False;
+ 	return True;
+ }

Index: rdp.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/rdp.c,v
retrieving revision 1.64
retrieving revision 1.65
diff -C2 -d -r1.64 -r1.65
*** rdp.c	17 Jun 2004 09:42:58 -0000	1.64
--- rdp.c	27 Jun 2004 17:51:54 -0000	1.65
***************
*** 35,38 ****
--- 35,39 ----
  extern int g_height;
  extern BOOL g_bitmap_cache;
+ extern BOOL g_bitmap_cache_persist_enable;
  
  uint8 *g_next_packet;
***************
*** 367,370 ****
--- 368,416 ----
  }
  
+ /* Inform the server on the contents of the persistent bitmap cache */
+ static void
+ rdp_enum_bmpcache2(void)
+ {
+ 	STREAM s;
+ 	uint8 idlist[BMPCACHE2_NUM_PSTCELLS * sizeof(BITMAP_ID)];
+ 	uint32 nids, offset, count, flags;
+ 
+ 	offset = 0;
+ 	nids = pstcache_enumerate(2, idlist);
+ 
+ 	while (offset < nids)
+ 	{
+ 		count = MIN(nids - offset, 169);
+ 
+ 		s = rdp_init_data(24 + count * sizeof(BITMAP_ID));
+ 
+ 		flags = 0;
+ 		if (offset == 0)
+ 			flags |= PDU_FLAG_FIRST;
+ 		if (nids - offset <= 169)
+ 			flags |= PDU_FLAG_LAST;
+ 
+ 		/* header */
+ 		out_uint32_le(s, 0);
+ 		out_uint16_le(s, count);
+ 		out_uint16_le(s, 0);
+ 		out_uint16_le(s, 0);
+ 		out_uint16_le(s, 0);
+ 		out_uint16_le(s, 0);
+ 		out_uint16_le(s, nids);
+ 		out_uint32_le(s, 0);
+ 		out_uint32_le(s, flags);
+ 
+ 		/* list */
+ 		out_uint8a(s, idlist + offset * sizeof(BITMAP_ID),
+ 				count * sizeof(BITMAP_ID));
+ 
+ 		s_mark_end(s);
+ 		rdp_send_data(s, 0x2b);
+ 
+ 		offset += 169;
+ 	}
+ }
+ 
  /* Send an (empty) font information PDU */
  static void
***************
*** 487,490 ****
--- 533,560 ----
  }
  
+ /* Output bitmap cache v2 capability set */
+ static void
+ rdp_out_bmpcache2_caps(STREAM s)
+ {
+ 	out_uint16_le(s, RDP_CAPSET_BMPCACHE2);
+ 	out_uint16_le(s, RDP_CAPLEN_BMPCACHE2);
+ 
+ 	out_uint16_le(s, g_bitmap_cache_persist_enable ? 1 : 0);	/* version */
+ 
+ 	out_uint16_le(s, 0x0300);	/* flags? number of caches? */
+ 
+ 	out_uint32_le(s, BMPCACHE2_C0_CELLS);
+ 	out_uint32_le(s, BMPCACHE2_C1_CELLS);
+ 	if (pstcache_init(2))
+ 	{
+ 		out_uint32_le(s, BMPCACHE2_NUM_PSTCELLS | BMPCACHE2_FLAG_PERSIST);
+ 	}
+ 	else
+ 	{
+ 		out_uint32_le(s, BMPCACHE2_C2_CELLS);
+ 	}
+ 	out_uint8s(s, 20);		/* other bitmap caches not used */
+ }
+ 
  /* Output control capability set */
  static void
***************
*** 546,579 ****
  }
  
! static uint8 canned_caps[] = {
! 	0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00, 0x04,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x0C, 0x00, 0x08, 0x00, 0x01,
! 	0x00, 0x00, 0x00, 0x0E, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00,
! 	0x10, 0x00, 0x34, 0x00, 0xFE,
! 	0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x08, 0x00,
! 	0xFE, 0x00, 0x08, 0x00, 0xFE,
! 	0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00, 0xFE, 0x00, 0x40, 0x00,
! 	0xFE, 0x00, 0x80, 0x00, 0xFE,
! 	0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x01,
! 	0x02, 0x00, 0x00, 0x00
  };
  
! /* Output unknown capability sets (number 13, 12, 14 and 16) */
  static void
! rdp_out_unknown_caps(STREAM s)
  {
! 	out_uint16_le(s, RDP_CAPSET_UNKNOWN);
! 	out_uint16_le(s, 0x58);
  
! 	out_uint8p(s, canned_caps, RDP_CAPLEN_UNKNOWN - 4);
  }
  
--- 616,654 ----
  }
  
! static uint8 caps_0x0d[] = {
! 	0x01, 0x00, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00,
! 	0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
! 	0x00, 0x00, 0x00, 0x00
  };
  
! static uint8 caps_0x0c[] = { 0x01, 0x00, 0x00, 0x00 };
! 
! static uint8 caps_0x0e[] = { 0x01, 0x00, 0x00, 0x00 };
! 
! static uint8 caps_0x10[] = {
! 	0xFE, 0x00, 0x04, 0x00, 0xFE, 0x00, 0x04, 0x00,
! 	0xFE, 0x00, 0x08, 0x00, 0xFE, 0x00, 0x08, 0x00,
! 	0xFE, 0x00, 0x10, 0x00, 0xFE, 0x00, 0x20, 0x00,
! 	0xFE, 0x00, 0x40, 0x00, 0xFE, 0x00, 0x80, 0x00,
! 	0xFE, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x08,
! 	0x00, 0x01, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00
! };
! 
! /* Output unknown capability sets */
  static void
! rdp_out_unknown_caps(STREAM s, uint16 id, uint16 length, uint8 *caps)
  {
! 	out_uint16_le(s, id);
! 	out_uint16_le(s, length);
  
! 	out_uint8p(s, caps, length - 4);
  }
  
***************
*** 589,593 ****
  		RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
  		RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
! 		RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE + RDP_CAPLEN_UNKNOWN + 4 /* w2k fix, why? */ ;
  
  	s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
--- 664,670 ----
  		RDP_CAPLEN_BMPCACHE + RDP_CAPLEN_COLCACHE +
  		RDP_CAPLEN_ACTIVATE + RDP_CAPLEN_CONTROL +
! 		RDP_CAPLEN_POINTER + RDP_CAPLEN_SHARE +
! 		0x58 + 0x08 + 0x08 + 0x34 /* unknown caps */ +
! 		4 /* w2k fix, why? */ ;
  
  	s = sec_init(sec_flags, 6 + 14 + caplen + sizeof(RDP_SOURCE));
***************
*** 609,613 ****
  	rdp_out_bitmap_caps(s);
  	rdp_out_order_caps(s);
! 	rdp_out_bmpcache_caps(s);
  	rdp_out_colcache_caps(s);
  	rdp_out_activate_caps(s);
--- 686,690 ----
  	rdp_out_bitmap_caps(s);
  	rdp_out_order_caps(s);
! 	g_use_rdp5 ? rdp_out_bmpcache2_caps(s) : rdp_out_bmpcache_caps(s);
  	rdp_out_colcache_caps(s);
  	rdp_out_activate_caps(s);
***************
*** 615,620 ****
  	rdp_out_pointer_caps(s);
  	rdp_out_share_caps(s);
- 	rdp_out_unknown_caps(s);
  
  	s_mark_end(s);
  	sec_send(s, sec_flags);
--- 692,701 ----
  	rdp_out_pointer_caps(s);
  	rdp_out_share_caps(s);
  
+ 	rdp_out_unknown_caps(s, 0x0d, 0x58, caps_0x0d); /* international? */
+ 	rdp_out_unknown_caps(s, 0x0c, 0x08, caps_0x0c);
+ 	rdp_out_unknown_caps(s, 0x0e, 0x08, caps_0x0e);
+ 	rdp_out_unknown_caps(s, 0x10, 0x34, caps_0x10); /* glyph cache? */
+ 				
  	s_mark_end(s);
  	sec_send(s, sec_flags);
***************
*** 660,664 ****
  	{
  		warning("screen size changed from %dx%d to %dx%d\n", g_width, g_height,
! 			width, height);
  		g_width = width;
  		g_height = height;
--- 741,745 ----
  	{
  		warning("screen size changed from %dx%d to %dx%d\n", g_width, g_height,
! 				width, height);
  		g_width = width;
  		g_height = height;
***************
*** 667,690 ****
  }
  
! /* Respond to a demand active PDU */
! static void
! process_demand_active(STREAM s)
  {
  	int n;
! 	uint8 type, *next;
! 	uint16 len_src_descriptor, len_combined_caps, num_capsets, capset_type, capset_length;
  
! 	in_uint32_le(s, g_rdp_shareid);
! 	in_uint16_le(s, len_src_descriptor);
! 	in_uint16_le(s, len_combined_caps);
! 	in_uint8s(s, len_src_descriptor);
  
! 	in_uint16_le(s, num_capsets);
  	in_uint8s(s, 2);	/* pad */
  
! 	DEBUG(("DEMAND_ACTIVE(id=0x%x,num_caps=%d)\n", g_rdp_shareid, num_capsets));
! 
! 	for (n = 0; n < num_capsets; n++)
  	{
  		in_uint16_le(s, capset_type);
  		in_uint16_le(s, capset_length);
--- 748,769 ----
  }
  
! /* Process server capabilities */
! void
! rdp_process_server_caps(STREAM s, uint16 length)
  {
  	int n;
! 	uint8 *next, *start;
! 	uint16 ncapsets, capset_type, capset_length;
  
! 	start = s->p;
  
! 	in_uint16_le(s, ncapsets);
  	in_uint8s(s, 2);	/* pad */
  
! 	for (n = 0; n < ncapsets; n++)
  	{
+ 		if (s->p > start + length)
+ 			return;
+ 
  		in_uint16_le(s, capset_type);
  		in_uint16_le(s, capset_length);
***************
*** 705,708 ****
--- 784,803 ----
  		s->p = next;
  	}
+ }
+ 
+ /* Respond to a demand active PDU */
+ static void
+ process_demand_active(STREAM s)
+ {
+ 	uint8 type;
+ 	uint16 len_src_descriptor, len_combined_caps;
+ 
+ 	in_uint32_le(s, g_rdp_shareid);
+ 	in_uint16_le(s, len_src_descriptor);
+ 	in_uint16_le(s, len_combined_caps);
+ 	in_uint8s(s, len_src_descriptor);
+ 
+ 	DEBUG(("DEMAND_ACTIVE(id=0x%x)\n", g_rdp_shareid));
+ 	rdp_process_server_caps(s, len_combined_caps);
  
  	rdp_send_confirm_active();
***************
*** 717,720 ****
--- 812,816 ----
  	if (g_use_rdp5)
  	{
+ 		rdp_enum_bmpcache2();
  		rdp_send_fonts(3);
  	}

Index: types.h
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/types.h,v
retrieving revision 1.19
retrieving revision 1.20
diff -C2 -d -r1.19 -r1.20
*** types.h	27 Apr 2004 12:55:33 -0000	1.19
--- types.h	27 Jun 2004 17:51:54 -0000	1.20
***************
*** 120,123 ****
--- 120,145 ----
  VCHANNEL;
  
+ typedef struct _BMPCACHEENTRY
+ {
+ 	HBITMAP bitmap;
+ 	uint32 usage;
+ 
+ }
+ BMPCACHEENTRY;
+ 
+ /* PSTCACHE */
+ 
+ typedef uint8 BITMAP_ID[8];
+ 
+ /* Header for an entry in the persistent bitmap cache file */
+ typedef struct _PSTCACHE_CELLHEADER
+ {
+ 	BITMAP_ID bitmap_id;
+ 	uint8 width, height;
+ 	uint16 length;
+ 	uint32 stamp;
+ }
+ CELLHEADER;
+ 
  #define MAX_CBSIZE 256
  

Index: xwin.c
===================================================================
RCS file: /cvsroot/rdesktop/rdesktop/xwin.c,v
retrieving revision 1.173
retrieving revision 1.174
diff -C2 -d -r1.173 -r1.174
*** xwin.c	16 Jun 2004 03:08:55 -0000	1.173
--- xwin.c	27 Jun 2004 17:51:54 -0000	1.174
***************
*** 48,51 ****
--- 48,53 ----
  BOOL g_Unobscured;		/* used for screenblt */
  static GC g_gc = NULL;
+ static GC g_create_bitmap_gc = NULL;
+ static GC g_create_glyph_gc = NULL;
  static Visual *g_visual;
  static int g_depth;
***************
*** 970,973 ****
--- 972,978 ----
  		g_gc = XCreateGC(g_display, g_wnd, 0, NULL);
  
+ 	if (g_create_bitmap_gc == NULL)
+ 		g_create_bitmap_gc = XCreateGC(g_display, g_wnd, 0, NULL);
+ 
  	if ((g_ownbackstore) && (g_backstore == 0))
  	{
***************
*** 1482,1486 ****
  			     (char *) tdata, width, height, bitmap_pad, 0);
  
! 	XPutImage(g_display, bitmap, g_gc, image, 0, 0, 0, 0, width, height);
  
  	XFree(image);
--- 1487,1491 ----
  			     (char *) tdata, width, height, bitmap_pad, 0);
  
! 	XPutImage(g_display, bitmap, g_create_bitmap_gc, image, 0, 0, 0, 0, width, height);
  
  	XFree(image);
***************
*** 1540,1549 ****
  	Pixmap bitmap;
  	int scanline;
- 	GC gc;
  
  	scanline = (width + 7) / 8;
  
  	bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
! 	gc = XCreateGC(g_display, bitmap, 0, NULL);
  
  	image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
--- 1545,1554 ----
  	Pixmap bitmap;
  	int scanline;
  
  	scanline = (width + 7) / 8;
  
  	bitmap = XCreatePixmap(g_display, g_wnd, width, height, 1);
! 	if (g_create_glyph_gc == 0)
! 		g_create_glyph_gc = XCreateGC(g_display, bitmap, 0, NULL);
  
  	image = XCreateImage(g_display, g_visual, 1, ZPixmap, 0, (char *) data,
***************
*** 1553,1560 ****
  	XInitImage(image);
  
! 	XPutImage(g_display, bitmap, gc, image, 0, 0, 0, 0, width, height);
  
  	XFree(image);
- 	XFreeGC(g_display, gc);
  	return (HGLYPH) bitmap;
  }
--- 1558,1564 ----
  	XInitImage(image);
  
! 	XPutImage(g_display, bitmap, g_create_glyph_gc, image, 0, 0, 0, 0, width, height);
  
  	XFree(image);
  	return (HGLYPH) bitmap;
  }



-------------------------------------------------------
This SF.Net email sponsored by Black Hat Briefings & Training.
Attend Black Hat Briefings & Training, Las Vegas July 24-29 - 
digital self defense, top technical experts, no vendor pitches, 
unmatched networking opportunities. Visit www.blackhat.com
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.