/* * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This 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 software 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 software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* * ultrazip.c - handle ultrazip encoding. * * This file shouldn't be compiled directly. It is included multiple times by * rfbproto.c, each time with a different definition of the macro BPP. For * each value of BPP, this file defines a function which handles an zlib * encoded rectangle with BPP bits per pixel. */ #define HandleUltraZipBPP CONCAT2E(HandleUltraZip,BPP) #define HandleUltraBPP CONCAT2E(HandleUltra,BPP) #define CARDBPP CONCAT3E(uint,BPP,_t) static rfbBool HandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh) { rfbZlibHeader hdr; int toRead=0; int inflateResult=0; lzo_uint uncompressedBytes = (( rw * rh ) * ( BPP / 8 )); if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) return FALSE; toRead = rfbClientSwap32IfLE(hdr.nBytes); if (toRead==0) return TRUE; if (uncompressedBytes==0) { rfbClientLog("ultra error: rectangle has 0 uncomressed bytes ((%dw * %dh) * (%d / 8))\n", rw, rh, BPP); return FALSE; } /* First make sure we have a large enough raw buffer to hold the * decompressed data. In practice, with a fixed BPP, fixed frame * buffer size and the first update containing the entire frame * buffer, this buffer allocation should only happen once, on the * first update. */ if ( client->raw_buffer_size < (int)uncompressedBytes) { if ( client->raw_buffer != NULL ) { free( client->raw_buffer ); } client->raw_buffer_size = uncompressedBytes; /* buffer needs to be aligned on 4-byte boundaries */ if ((client->raw_buffer_size % 4)!=0) client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); client->raw_buffer = (char*) malloc( client->raw_buffer_size ); } /* allocate enough space to store the incoming compressed packet */ if ( client->ultra_buffer_size < toRead ) { if ( client->ultra_buffer != NULL ) { free( client->ultra_buffer ); } client->ultra_buffer_size = toRead; /* buffer needs to be aligned on 4-byte boundaries */ if ((client->ultra_buffer_size % 4)!=0) client->ultra_buffer_size += (4-(client->ultra_buffer_size % 4)); client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); } /* Fill the buffer, obtaining data from the server. */ if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) return FALSE; /* uncompress the data */ uncompressedBytes = client->raw_buffer_size; inflateResult = lzo1x_decompress( (lzo_byte *)client->ultra_buffer, toRead, (lzo_byte *)client->raw_buffer, (lzo_uintp) &uncompressedBytes, NULL); if ((rw * rh * (BPP / 8)) != uncompressedBytes) rfbClientLog("Ultra decompressed too little (%d < %d)", (rw * rh * (BPP / 8)), uncompressedBytes); /* Put the uncompressed contents of the update on the screen. */ if ( inflateResult == LZO_E_OK ) { CopyRectangle(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh); } else { rfbClientLog("ultra decompress returned error: %d\n", inflateResult); return FALSE; } return TRUE; } /* UltraZip is like rre in that it is composed of subrects */ static rfbBool HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) { rfbZlibHeader hdr; int i=0; int toRead=0; int inflateResult=0; unsigned char *ptr=NULL; lzo_uint uncompressedBytes = ry + (rw * 65535); unsigned int numCacheRects = rx; if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) return FALSE; toRead = rfbClientSwap32IfLE(hdr.nBytes); if (toRead==0) return TRUE; if (uncompressedBytes==0) { rfbClientLog("ultrazip error: rectangle has 0 uncomressed bytes (%dy + (%dw * 65535)) (%d rectangles)\n", ry, rw, rx); return FALSE; } /* First make sure we have a large enough raw buffer to hold the * decompressed data. In practice, with a fixed BPP, fixed frame * buffer size and the first update containing the entire frame * buffer, this buffer allocation should only happen once, on the * first update. */ if ( client->raw_buffer_size < (int)(uncompressedBytes + 500)) { if ( client->raw_buffer != NULL ) { free( client->raw_buffer ); } client->raw_buffer_size = uncompressedBytes + 500; /* buffer needs to be aligned on 4-byte boundaries */ if ((client->raw_buffer_size % 4)!=0) client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); client->raw_buffer = (char*) malloc( client->raw_buffer_size ); } /* allocate enough space to store the incoming compressed packet */ if ( client->ultra_buffer_size < toRead ) { if ( client->ultra_buffer != NULL ) { free( client->ultra_buffer ); } client->ultra_buffer_size = toRead; client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); } /* Fill the buffer, obtaining data from the server. */ if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) return FALSE; /* uncompress the data */ uncompressedBytes = client->raw_buffer_size; inflateResult = lzo1x_decompress( (lzo_byte *)client->ultra_buffer, toRead, (lzo_byte *)client->raw_buffer, &uncompressedBytes, NULL); if ( inflateResult != LZO_E_OK ) { rfbClientLog("ultra decompress returned error: %d\n", inflateResult); return FALSE; } /* Put the uncompressed contents of the update on the screen. */ ptr = (unsigned char *)client->raw_buffer; for (i=0; i<numCacheRects; i++) { unsigned short sx, sy, sw, sh; unsigned int se; memcpy((char *)&sx, ptr, 2); ptr += 2; memcpy((char *)&sy, ptr, 2); ptr += 2; memcpy((char *)&sw, ptr, 2); ptr += 2; memcpy((char *)&sh, ptr, 2); ptr += 2; memcpy((char *)&se, ptr, 4); ptr += 4; sx = rfbClientSwap16IfLE(sx); sy = rfbClientSwap16IfLE(sy); sw = rfbClientSwap16IfLE(sw); sh = rfbClientSwap16IfLE(sh); se = rfbClientSwap32IfLE(se); if (se == rfbEncodingRaw) { CopyRectangle(client, (unsigned char *)ptr, sx, sy, sw, sh); ptr += ((sw * sh) * (BPP / 8)); } } return TRUE; } #undef CARDBPP