#include #include #include "lx.h" #include "proto.h" #include "internal.h" typedef struct priv_GetProperty PRIV_GetProperty; struct priv_GetProperty { int *formatp; LX_XID *typep; unsigned int *afterp; unsigned int *lenp; void **valuep; } ; static void done_GetProperty(LX_OP *op, const unsigned char *rep) { PRIV_GetProperty *p; unsigned int datalen; unsigned int replylen; unsigned long long int wantlen; int fmt; int shift; size_t dbufsize; unsigned char *databuf; int i; LX_XID acttype; p = op->reqpriv; do <"ret"> { fmt = rep[1]; datalen = r_card32(rep+16); replylen = r_card32(rep+4); if ((fmt == 0) && (datalen != 0)) { lx__protoerr(op->conn,"GetProperty returned format=0 but datalen %d",datalen); break <"ret">; } switch (fmt) { case 0: break; case 8: shift = 0; break; case 16: shift = 1; break; case 32: shift = 2; break; default: lx__protoerr(op->conn,"GetProperty returned invalid format %d",fmt); break <"ret">; } // Use long long to avoid overflow wantlen = (datalen + (3ULL>>shift)) >> (2-shift); if (wantlen > 0xffffffffULL) { lx__protoerr(op->conn,"GetProperty response requires impossible length %lld)",wantlen); break <"ret">; } if (replylen != wantlen) { lx__protoerr(op->conn,"GetProperty response length wrong (%u, expecting %lld)",r_card32(rep+4),wantlen); break <"ret">; } if (p->valuep) { if (fmt == 0) { *p->valuep = 0; } else { dbufsize = ((size_t)datalen) << shift; if ((dbufsize >> shift) != datalen) { lx__protoerr(op->conn,"GetProperty response requires too much data (%llu, max size_t is %llu)",(datalen+0ULL)<; } databuf = malloc(dbufsize); if (! databuf) { lx__nomem_fail(op->conn); break <"ret">; } switch (fmt) { case 8: bcopy(rep+32,databuf,datalen); break; case 16: for (i=datalen-1;i>=0;i--) ((unsigned short int *)databuf)[i] = r_card16(rep+32+(2*i)); break; case 32: for (i=datalen-1;i>=0;i--) ((unsigned int *)databuf)[i] = r_card32(rep+32+(4*i)); break; } *p->valuep = databuf; } } if (p->formatp) *p->formatp = fmt; if (p->typep) { acttype = r_card32(rep+8); if (acttype == 0) acttype = LX_ATOM_None; *p->typep = acttype; } if (p->afterp) *p->afterp = r_card32(rep+12); if (p->lenp) *p->lenp = datalen; } while (0); op->reqpriv = 0; free(p); } LX_OP *lx_GetProperty( LX_CONN *xc, LX_XID window, LX_XID property, LX_XID type, unsigned int offset, unsigned int len, int delete, int *formatp, LX_XID *typep, unsigned int *afterp, int *lenp, void **valuep ) { unsigned char req[24]; PRIV_GetProperty *p; if (xc->flags & XCF_FAIL) { lx__bad_call(xc,"lx_GetProperty"); return(0); } p = malloc(sizeof(PRIV_GetProperty)); if (! p) { lx__nomem_fail(xc); return(0); } if (type == LX_ATOM_AnyPropertyType) type = 0; p->formatp = formatp; p->typep = typep; p->afterp = afterp; p->lenp = lenp; p->valuep = valuep; req[0] = XP_REQ_GetProperty; req[1] = lx__boolean_to_proto(delete); w_card16(&req[2],6); w_card32(&req[4],window); w_card32(&req[8],property); w_card32(&req[12],type); w_card32(&req[16],offset); w_card32(&req[20],len); return(lx__expect_reply(xc,&req[0],-1,&done_GetProperty,p)); }