1a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 2a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Copyright (C) 2000 Tridia Corporation. All Rights Reserved. 3a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. 4a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 5a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * This is free software; you can redistribute it and/or modify 6a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * it under the terms of the GNU General Public License as published by 7a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * the Free Software Foundation; either version 2 of the License, or 8a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * (at your option) any later version. 9a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 10a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * This software is distributed in the hope that it will be useful, 11a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * but WITHOUT ANY WARRANTY; without even the implied warranty of 12a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * GNU General Public License for more details. 14a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 15a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * You should have received a copy of the GNU General Public License 16a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * along with this software; if not, write to the Free Software 17a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 18a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * USA. 19a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 20a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 21a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* 22a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * ultrazip.c - handle ultrazip encoding. 23a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * 24a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * This file shouldn't be compiled directly. It is included multiple times by 25a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * rfbproto.c, each time with a different definition of the macro BPP. For 26a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * each value of BPP, this file defines a function which handles an zlib 27a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * encoded rectangle with BPP bits per pixel. 28a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 29a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 30a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define HandleUltraZipBPP CONCAT2E(HandleUltraZip,BPP) 31a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define HandleUltraBPP CONCAT2E(HandleUltra,BPP) 32a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#define CARDBPP CONCAT3E(uint,BPP,_t) 33a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 34a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic rfbBool 35a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatHandleUltraBPP (rfbClient* client, int rx, int ry, int rw, int rh) 36a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat{ 37a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbZlibHeader hdr; 38a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int toRead=0; 39a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int inflateResult=0; 40a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat lzo_uint uncompressedBytes = (( rw * rh ) * ( BPP / 8 )); 41a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 42a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) 43a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 44a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 45a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat toRead = rfbClientSwap32IfLE(hdr.nBytes); 46a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (toRead==0) return TRUE; 47a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 48a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (uncompressedBytes==0) 49a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 50a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbClientLog("ultra error: rectangle has 0 uncomressed bytes ((%dw * %dh) * (%d / 8))\n", rw, rh, BPP); 51a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 52a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 53a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 54a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* First make sure we have a large enough raw buffer to hold the 55a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * decompressed data. In practice, with a fixed BPP, fixed frame 56a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * buffer size and the first update containing the entire frame 57a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * buffer, this buffer allocation should only happen once, on the 58a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * first update. 59a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 60a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->raw_buffer_size < (int)uncompressedBytes) { 61a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->raw_buffer != NULL ) { 62a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat free( client->raw_buffer ); 63a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 64a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer_size = uncompressedBytes; 65a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* buffer needs to be aligned on 4-byte boundaries */ 66a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ((client->raw_buffer_size % 4)!=0) 67a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); 68a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 69a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 70a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 71a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* allocate enough space to store the incoming compressed packet */ 72a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->ultra_buffer_size < toRead ) { 73a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->ultra_buffer != NULL ) { 74a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat free( client->ultra_buffer ); 75a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 76a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->ultra_buffer_size = toRead; 77a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* buffer needs to be aligned on 4-byte boundaries */ 78a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ((client->ultra_buffer_size % 4)!=0) 79a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->ultra_buffer_size += (4-(client->ultra_buffer_size % 4)); 80a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); 81a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 82a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 83a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Fill the buffer, obtaining data from the server. */ 84a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) 85a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 86a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 87a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* uncompress the data */ 88a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat uncompressedBytes = client->raw_buffer_size; 89a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat inflateResult = lzo1x_decompress( 90a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat (lzo_byte *)client->ultra_buffer, toRead, 91a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat (lzo_byte *)client->raw_buffer, (lzo_uintp) &uncompressedBytes, 92a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat NULL); 93a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 94a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 95a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ((rw * rh * (BPP / 8)) != uncompressedBytes) 96a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbClientLog("Ultra decompressed too little (%d < %d)", (rw * rh * (BPP / 8)), uncompressedBytes); 97a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 98a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Put the uncompressed contents of the update on the screen. */ 99a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( inflateResult == LZO_E_OK ) 100a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 101a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat CopyRectangle(client, (unsigned char *)client->raw_buffer, rx, ry, rw, rh); 102a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 103a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat else 104a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 105a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbClientLog("ultra decompress returned error: %d\n", 106a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat inflateResult); 107a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 108a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 109a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return TRUE; 110a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} 111a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 112a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 113a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat/* UltraZip is like rre in that it is composed of subrects */ 114a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehatstatic rfbBool 115a430b2b5ca4f0967836f5820e8f03adc17fc0a24San MehatHandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) 116a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat{ 117a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbZlibHeader hdr; 118a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int i=0; 119a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int toRead=0; 120a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat int inflateResult=0; 121a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat unsigned char *ptr=NULL; 122a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat lzo_uint uncompressedBytes = ry + (rw * 65535); 123a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat unsigned int numCacheRects = rx; 124a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 125a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (!ReadFromRFBServer(client, (char *)&hdr, sz_rfbZlibHeader)) 126a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 127a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 128a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat toRead = rfbClientSwap32IfLE(hdr.nBytes); 129a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 130a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (toRead==0) return TRUE; 131a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 132a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (uncompressedBytes==0) 133a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 134a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbClientLog("ultrazip error: rectangle has 0 uncomressed bytes (%dy + (%dw * 65535)) (%d rectangles)\n", ry, rw, rx); 135a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 136a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 137a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 138a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* First make sure we have a large enough raw buffer to hold the 139a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * decompressed data. In practice, with a fixed BPP, fixed frame 140a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * buffer size and the first update containing the entire frame 141a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * buffer, this buffer allocation should only happen once, on the 142a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat * first update. 143a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat */ 144a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->raw_buffer_size < (int)(uncompressedBytes + 500)) { 145a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->raw_buffer != NULL ) { 146a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat free( client->raw_buffer ); 147a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 148a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer_size = uncompressedBytes + 500; 149a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* buffer needs to be aligned on 4-byte boundaries */ 150a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ((client->raw_buffer_size % 4)!=0) 151a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer_size += (4-(client->raw_buffer_size % 4)); 152a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->raw_buffer = (char*) malloc( client->raw_buffer_size ); 153a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 154a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 155a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 156a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* allocate enough space to store the incoming compressed packet */ 157a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->ultra_buffer_size < toRead ) { 158a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( client->ultra_buffer != NULL ) { 159a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat free( client->ultra_buffer ); 160a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 161a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->ultra_buffer_size = toRead; 162a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat client->ultra_buffer = (char*) malloc( client->ultra_buffer_size ); 163a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 164a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 165a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Fill the buffer, obtaining data from the server. */ 166a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (!ReadFromRFBServer(client, client->ultra_buffer, toRead)) 167a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 168a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 169a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* uncompress the data */ 170a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat uncompressedBytes = client->raw_buffer_size; 171a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat inflateResult = lzo1x_decompress( 172a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat (lzo_byte *)client->ultra_buffer, toRead, 173a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat (lzo_byte *)client->raw_buffer, &uncompressedBytes, NULL); 174a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if ( inflateResult != LZO_E_OK ) 175a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 176a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat rfbClientLog("ultra decompress returned error: %d\n", 177a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat inflateResult); 178a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return FALSE; 179a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 180a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 181a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat /* Put the uncompressed contents of the update on the screen. */ 182a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat ptr = (unsigned char *)client->raw_buffer; 183a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat for (i=0; i<numCacheRects; i++) 184a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 185a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat unsigned short sx, sy, sw, sh; 186a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat unsigned int se; 187a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 188a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&sx, ptr, 2); ptr += 2; 189a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&sy, ptr, 2); ptr += 2; 190a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&sw, ptr, 2); ptr += 2; 191a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&sh, ptr, 2); ptr += 2; 192a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat memcpy((char *)&se, ptr, 4); ptr += 4; 193a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 194a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat sx = rfbClientSwap16IfLE(sx); 195a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat sy = rfbClientSwap16IfLE(sy); 196a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat sw = rfbClientSwap16IfLE(sw); 197a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat sh = rfbClientSwap16IfLE(sh); 198a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat se = rfbClientSwap32IfLE(se); 199a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 200a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat if (se == rfbEncodingRaw) 201a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat { 202a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat CopyRectangle(client, (unsigned char *)ptr, sx, sy, sw, sh); 203a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat ptr += ((sw * sh) * (BPP / 8)); 204a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 205a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat } 206a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 207a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat return TRUE; 208a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat} 209a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat 210a430b2b5ca4f0967836f5820e8f03adc17fc0a24San Mehat#undef CARDBPP 211