#include "dxpcconf.h" #include #include "X-headers.H" #include "ServerChannel.H" #include "EncodeBuffer.H" #include "DecodeBuffer.H" #include "util.H" ServerChannel::ServerChannel(int xServerFD, unsigned int statisticsLevel) : readBuffer_(xServerFD, this), fd_(xServerFD), firstRequest_(1), firstReply_(1), statisticsLevel_(statisticsLevel) { if (compressImages) { decompresser = new Decompresser(compressImages); } else { decompresser = 0; } } ServerChannel::~ServerChannel() { if (statisticsLevel_ > 0) { *logofs << "\n*** dxpc Server-side Compression Statistics ***\n"; unsigned int replyBitsIn, replyBitsOut; if (statisticsLevel_ >= 2) { *logofs << "\nCompression of replies by request message type:\n"; } replyStats_.summarize(replyBitsIn, replyBitsOut, (statisticsLevel_ >= 2)); if (statisticsLevel_ >= 2) { *logofs << "\nCompression of events and errors by message type:\n"; } unsigned int bitsIn, bitsOut; stats_.summarize(bitsIn, bitsOut, (statisticsLevel_ >= 2)); if (statisticsLevel_ >= 2) { *logofs << '\n' << framingBitsOut_ << " bits used for dxpc message framing and multiplexing\n"; } unsigned int totalBitsIn = bitsIn + replyBitsIn; unsigned int totalBitsOut = bitsOut + replyBitsOut + framingBitsOut_; *logofs << "\nOverall compression:" << ENDL << " " << totalBitsIn << " bits compressed to " << totalBitsOut << ENDL; if (totalBitsOut > 0) { *logofs << " (" << (float) totalBitsIn / (float) totalBitsOut << ":1 compression ratio)" << ENDL << ENDL; } } if (decompresser) { delete decompresser; decompresser = 0; } } int ServerChannel::doRead(EncodeBuffer & encodeBuffer) { if (!readBuffer_.doRead()) return 0; const unsigned char *buffer; unsigned int size; while ((buffer = readBuffer_.getMessage(size)) != 0) { if (firstReply_) { imageByteOrder_ = buffer[30]; bitmapBitOrder_ = buffer[31]; scanlineUnit_ = buffer[32]; scanlinePad_ = buffer[33]; firstReply_ = 0; encodeBuffer.encodeValue((unsigned int) buffer[0], 8); encodeBuffer.encodeValue((unsigned int) buffer[1], 8); encodeBuffer.encodeValue(GetUINT(buffer + 2, bigEndian_), 16); encodeBuffer.encodeValue(GetUINT(buffer + 4, bigEndian_), 16); encodeBuffer.encodeValue(GetUINT(buffer + 6, bigEndian_), 16); if (ServerCache::lastInitReply.compare(size - 8, buffer + 8)) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); for (unsigned int i = 8; i < size; i++) encodeBuffer.encodeValue((unsigned int) buffer[i], 8); } } else { if (buffer[0] == 1) { // reply unsigned int sequenceNum = GetUINT(buffer + 2, bigEndian_); unsigned int sequenceNumDiff = sequenceNum - serverCache_.lastSequenceNum; serverCache_.lastSequenceNum = sequenceNum; unsigned char opcode = *buffer; encodeBuffer.encodeCachedValue(opcode, 8, serverCache_. opcodeCache[serverCache_. lastOpcode]); serverCache_.lastOpcode = opcode; encodeBuffer.encodeCachedValue(sequenceNumDiff, 16, serverCache_. replySequenceNumCache, 7); unsigned short int nextSequenceNum; unsigned int requestOpcode = 256; unsigned char nextOpcode; if (sequenceNumQueue_.peek(nextSequenceNum, nextOpcode) && (nextSequenceNum == sequenceNum)) { // we've found the request that generated this reply, so it's // possible to compress the reply based on the request type unsigned int requestData[3]; sequenceNumQueue_.pop(nextSequenceNum, nextOpcode, requestData[0], requestData[1], requestData[2]); requestOpcode = nextOpcode; switch (nextOpcode) { case X_AllocColor: { const unsigned char *nextSrc = buffer + 8; for (unsigned int i = 0; i < 3; i++) { unsigned int colorValue = GetUINT(nextSrc, bigEndian_); nextSrc += 2; if (colorValue == requestData[i]) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); encodeBuffer.encodeValue(colorValue - colorValue, 16, 6); } } unsigned int pixel = GetULONG(buffer + 16, bigEndian_); encodeBuffer.encodeValue(pixel, 32, 9); } break; case X_GetAtomName: { unsigned int nameLength = GetUINT(buffer + 8, bigEndian_); encodeBuffer.encodeValue(nameLength, 16, 6); const unsigned char *nextSrc = buffer + 32; clientCache_.internAtomTextCompressor.reset(); for (unsigned int i = 0; i < nameLength; i++) clientCache_.internAtomTextCompressor. encodeChar(*nextSrc++, encodeBuffer); } break; case X_GetGeometry: { encodeBuffer.encodeCachedValue(buffer[1], 8, serverCache_. depthCache); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. getGeometryRootCache, 9); const unsigned char *nextSrc = buffer + 12; for (unsigned int i = 0; i < 5; i++) { encodeBuffer. encodeCachedValue(GetUINT (nextSrc, bigEndian_), 16, *serverCache_. getGeometryGeomCache[i], 8); nextSrc += 2; } } break; case X_GetInputFocus: { encodeBuffer.encodeValue((unsigned int) buffer[1], 2); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. getInputFocusWindowCache, 9); } break; case X_GetKeyboardMapping: { unsigned int keysymsPerKeycode = (unsigned int) buffer[1]; if (ServerCache::getKeyboardMappingLastMap. compare(size - 32, buffer + 32) && (keysymsPerKeycode == ServerCache:: getKeyboardMappingLastKeysymsPerKeycode)) { encodeBuffer.encodeValue(1, 1); break; } ServerCache:: getKeyboardMappingLastKeysymsPerKeycode = keysymsPerKeycode; encodeBuffer.encodeValue(0, 1); unsigned int numKeycodes = (((size - 32) / keysymsPerKeycode) >> 2); encodeBuffer.encodeValue(numKeycodes, 8); encodeBuffer.encodeValue(keysymsPerKeycode, 8, 4); const unsigned char *nextSrc = buffer + 32; unsigned char previous = 0; for (unsigned int count = numKeycodes * keysymsPerKeycode; count; --count) { unsigned int keysym = GetULONG(nextSrc, bigEndian_); nextSrc += 4; if (keysym == NoSymbol) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); unsigned int first3Bytes = (keysym >> 8); encodeBuffer. encodeCachedValue(first3Bytes, 24, serverCache_. getKeyboardMappingKeysymCache, 9); unsigned char lastByte = (unsigned char) (keysym & 0xff); encodeBuffer.encodeCachedValue(lastByte - previous, 8, serverCache_. getKeyboardMappingLastByteCache, 5); previous = lastByte; } } } break; case X_GetModifierMapping: { encodeBuffer.encodeValue((unsigned int) buffer[1], 8); const unsigned char *nextDest = buffer + 32; if (ServerCache::getModifierMappingLastMap. compare(size - 32, nextDest)) { encodeBuffer.encodeValue(1, 1); break; } encodeBuffer.encodeValue(0, 1); for (unsigned int count = size - 32; count; count--) { unsigned char next = *nextDest++; if (next == 0) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); encodeBuffer.encodeValue(next, 8); } } } break; case X_GetProperty: { unsigned char format = (unsigned int) buffer[1]; encodeBuffer.encodeCachedValue(format, 8, serverCache_. getPropertyFormatCache); unsigned int numBytes = GetULONG(buffer + 16, bigEndian_); encodeBuffer.encodeValue(numBytes, 32, 9); if (format == 16) numBytes <<= 1; else if (format == 32) numBytes <<= 2; encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. getPropertyTypeCache, 9); encodeBuffer. encodeValue(GetULONG(buffer + 12, bigEndian_), 32, 9); const unsigned char *nextSrc = buffer + 32; if (format == 8) { if (requestData[0] == XA_RESOURCE_MANAGER) { if (ServerCache::xResources. compare(numBytes, buffer + 32)) { encodeBuffer.encodeValue(1, 1); break; } encodeBuffer.encodeValue(0, 1); } serverCache_.getPropertyTextCompressor. reset(); for (unsigned int i = 0; i < numBytes; i++) { unsigned char nextChar; serverCache_.getPropertyTextCompressor. encodeChar(nextChar = *nextSrc++, encodeBuffer); if (nextChar == 10) { serverCache_. getPropertyTextCompressor. reset(nextChar); } } } else { for (unsigned int i = 0; i < numBytes; i++) encodeBuffer. encodeValue((unsigned int) *nextSrc++, 8); } } break; case X_GetSelectionOwner: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. getSelectionOwnerCache, 9); } break; case X_GetWindowAttributes: { encodeBuffer.encodeValue((unsigned int) buffer[1], 2); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_.visualCache, 9); encodeBuffer. encodeCachedValue(GetUINT (buffer + 12, bigEndian_), 16, serverCache_. getWindowAttributesClassCache, 3); encodeBuffer.encodeCachedValue(buffer[14], 8, serverCache_. getWindowAttributesBitGravityCache); encodeBuffer.encodeCachedValue(buffer[15], 8, serverCache_. getWindowAttributesWinGravityCache); encodeBuffer. encodeCachedValue(GetULONG (buffer + 16, bigEndian_), 32, serverCache_. getWindowAttributesPlanesCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 20, bigEndian_), 32, serverCache_. getWindowAttributesPixelCache, 9); encodeBuffer. encodeValue((unsigned int) buffer[24], 1); encodeBuffer. encodeValue((unsigned int) buffer[25], 1); encodeBuffer. encodeValue((unsigned int) buffer[26], 2); encodeBuffer. encodeValue((unsigned int) buffer[27], 1); encodeBuffer. encodeCachedValue(GetULONG (buffer + 28, bigEndian_), 29, serverCache_.colormapCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 32, bigEndian_), 32, serverCache_. getWindowAttributesAllEventsCache); encodeBuffer. encodeCachedValue(GetULONG (buffer + 36, bigEndian_), 32, serverCache_. getWindowAttributesYourEventsCache); encodeBuffer. encodeCachedValue(GetUINT (buffer + 40, bigEndian_), 16, serverCache_. getWindowAttributesDontPropagateCache); } break; case X_GrabKeyboard: case X_GrabPointer: { encodeBuffer.encodeValue((unsigned int) buffer[1], 3); } break; case X_InternAtom: { encodeBuffer. encodeValue(GetULONG(buffer + 8, bigEndian_), 29, 9); } break; case X_ListExtensions: { encodeBuffer. encodeValue(GetULONG(buffer + 4, bigEndian_), 32, 8); unsigned int numExtensions = (unsigned int) buffer[1]; encodeBuffer.encodeValue(numExtensions, 8); const unsigned char *nextSrc = buffer + 32; for (; numExtensions; numExtensions--) { unsigned int length = (unsigned int) (*nextSrc++); encodeBuffer.encodeValue(length, 8); if (!strncmp((char *) nextSrc, "MIT-SHM", 7)) memcpy((unsigned char *) nextSrc, "NOT-SHM", 7); for (; length; length--) encodeBuffer. encodeValue((unsigned int) (*nextSrc++), 8); } } break; case X_ListFonts: { encodeBuffer. encodeValue(GetULONG(buffer + 4, bigEndian_), 32, 8); unsigned int numFonts = GetUINT(buffer + 8, bigEndian_); encodeBuffer.encodeValue(numFonts, 16, 6); const unsigned char *nextSrc = buffer + 32; for (; numFonts; numFonts--) { unsigned int length = (unsigned int) (*nextSrc++); encodeBuffer.encodeValue(length, 8); serverCache_.getPropertyTextCompressor. reset(); for (; length; length--) serverCache_.getPropertyTextCompressor. encodeChar(*nextSrc++, encodeBuffer); } } break; case X_LookupColor: case X_AllocNamedColor: { const unsigned char *nextSrc = buffer + 8; if (nextOpcode == X_AllocNamedColor) { encodeBuffer. encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); nextSrc += 4; } unsigned int count = 3; do { unsigned int exactColor = GetUINT(nextSrc, bigEndian_); encodeBuffer.encodeValue(exactColor, 16, 9); unsigned int visualColor = GetUINT(nextSrc + 6, bigEndian_) - exactColor; encodeBuffer.encodeValue(visualColor, 16, 5); nextSrc += 2; } while (--count); } break; case X_QueryBestSize: { encodeBuffer. encodeValue(GetUINT(buffer + 8, bigEndian_), 16, 8); encodeBuffer. encodeValue(GetUINT(buffer + 10, bigEndian_), 16, 8); } break; case X_QueryColors: { unsigned int numColors = ((size - 32) >> 3); const unsigned char *nextSrc = buffer + 40; unsigned char *nextDest = (unsigned char *) buffer + 38; for (unsigned int c = 1; c < numColors; c++) { for (unsigned int i = 0; i < 6; i++) *nextDest++ = *nextSrc++; nextSrc += 2; } unsigned int colorsLength = numColors * 6; if (serverCache_.queryColorsLastReply. compare(colorsLength, buffer + 32)) encodeBuffer.encodeValue(1, 1); else { const unsigned char *nextSrc = buffer + 32; encodeBuffer.encodeValue(0, 1); encodeBuffer.encodeValue(numColors, 16, 5); for (numColors *= 3; numColors; numColors--) { encodeBuffer. encodeValue(GetUINT (nextSrc, bigEndian_), 16); nextSrc += 2; } } } break; case X_QueryExtension: { // requestData[0] will be nonzero if the request is for // an extension that dxpc should hide, like MIT-SHM if (requestData[0]) { encodeBuffer.encodeValue(0, 1); encodeBuffer.encodeValue(0, 8); } else { encodeBuffer. encodeValue((unsigned int) buffer[8], 1); encodeBuffer. encodeValue((unsigned int) buffer[9], 8); } encodeBuffer. encodeValue((unsigned int) buffer[10], 8); encodeBuffer. encodeValue((unsigned int) buffer[11], 8); } break; case X_QueryFont: { unsigned int numProperties = GetUINT(buffer + 46, bigEndian_); unsigned int numCharInfos = GetULONG(buffer + 56, bigEndian_); encodeBuffer.encodeValue(numProperties, 16, 8); encodeBuffer.encodeValue(numCharInfos, 32, 10); encodeCharInfo_(buffer + 8, encodeBuffer); encodeCharInfo_(buffer + 24, encodeBuffer); encodeBuffer. encodeValue(GetUINT(buffer + 40, bigEndian_), 16, 9); encodeBuffer. encodeValue(GetUINT(buffer + 42, bigEndian_), 16, 9); encodeBuffer. encodeValue(GetUINT(buffer + 44, bigEndian_), 16, 9); encodeBuffer. encodeValue((unsigned int) buffer[48], 1); encodeBuffer. encodeValue((unsigned int) buffer[49], 8); encodeBuffer. encodeValue((unsigned int) buffer[50], 8); encodeBuffer. encodeValue((unsigned int) buffer[51], 1); encodeBuffer. encodeValue(GetUINT(buffer + 52, bigEndian_), 16, 9); encodeBuffer. encodeValue(GetUINT(buffer + 54, bigEndian_), 16, 9); const unsigned char *nextSrc = buffer + 60; unsigned int index; if (ServerCache::queryFontFontCache. lookup(numProperties * 8 + numCharInfos * 12, nextSrc, index)) { encodeBuffer.encodeValue(1, 1); encodeBuffer.encodeValue(index, 4); break; } encodeBuffer.encodeValue(0, 1); for (; numProperties; numProperties--) { encodeBuffer. encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9); encodeBuffer. encodeValue(GetULONG (nextSrc + 4, bigEndian_), 32, 9); nextSrc += 8; } for (; numCharInfos; numCharInfos--) { encodeCharInfo_(nextSrc, encodeBuffer); nextSrc += 12; } } break; case X_QueryPointer: { encodeBuffer.encodeValue((unsigned int) buffer[1], 1); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. queryPointerRootCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 12, bigEndian_), 29, serverCache_. queryPointerChildCache, 9); unsigned int rootX = GetUINT(buffer + 16, bigEndian_); unsigned int rootY = GetUINT(buffer + 18, bigEndian_); unsigned int eventX = GetUINT(buffer + 20, bigEndian_); unsigned int eventY = GetUINT(buffer + 22, bigEndian_); eventX -= rootX; eventY -= rootY; encodeBuffer.encodeCachedValue(rootX - serverCache_. motionNotifyLastRootX, 16, serverCache_. motionNotifyRootXCache, 8); serverCache_.motionNotifyLastRootX = rootX; encodeBuffer.encodeCachedValue(rootY - serverCache_. motionNotifyLastRootY, 16, serverCache_. motionNotifyRootYCache, 8); serverCache_.motionNotifyLastRootY = rootY; encodeBuffer.encodeCachedValue(eventX, 16, serverCache_. motionNotifyEventXCache, 8); encodeBuffer.encodeCachedValue(eventY, 16, serverCache_. motionNotifyEventYCache, 8); encodeBuffer. encodeCachedValue(GetUINT (buffer + 24, bigEndian_), 16, serverCache_. motionNotifyStateCache); } break; case X_QueryTree: { encodeBuffer.encodeValue(buffer[1], 8); encodeBuffer. encodeValue(GetULONG(buffer + 4, bigEndian_), 32); for (unsigned int i = 8; i < size; i++) encodeBuffer. encodeValue((unsigned int) buffer[i], 8); } break; case X_TranslateCoords: { encodeBuffer.encodeValue((unsigned int) buffer[1], 1); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. translateCoordsChildCache, 9); encodeBuffer. encodeCachedValue(GetUINT (buffer + 12, bigEndian_), 16, serverCache_. translateCoordsXCache, 8); encodeBuffer. encodeCachedValue(GetUINT (buffer + 14, bigEndian_), 16, serverCache_. translateCoordsYCache, 8); } break; default: { CERR << "assertion failed in ServerXReader::processMessage():\n" << " no matching request for reply with sequence number " << sequenceNum << ENDL; } } } else { encodeBuffer.encodeValue(buffer[1], 8); encodeBuffer.encodeValue(GetULONG(buffer + 4, bigEndian_), 32); for (unsigned int i = 8; i < size; i++) encodeBuffer.encodeValue((unsigned int) buffer[i], 8); } replyStats_.add(requestOpcode, size << 3, encodeBuffer.getCumulativeBitsWritten()); } else { // event or error unsigned int sequenceNum = GetUINT(buffer + 2, bigEndian_); unsigned int sequenceNumDiff = sequenceNum - serverCache_.lastSequenceNum; serverCache_.lastSequenceNum = sequenceNum; unsigned int opcode = (unsigned int) *buffer; encodeBuffer.encodeCachedValue(opcode, 8, serverCache_. opcodeCache[serverCache_. lastOpcode]); serverCache_.lastOpcode = opcode; encodeBuffer.encodeCachedValue(sequenceNumDiff, 16, serverCache_. eventSequenceNumCache, 7); // check if this is an error that matches a sequence number for // which we were expecting a reply unsigned short int dummySequenceNum; unsigned char dummyOpcode; if (sequenceNumQueue_.peek(dummySequenceNum, dummyOpcode) && ((unsigned int) dummySequenceNum == sequenceNum)) sequenceNumQueue_.pop(dummySequenceNum, dummyOpcode); switch (*buffer) { case 0: { unsigned char code = buffer[1]; encodeBuffer.encodeCachedValue(code, 8, serverCache_. errorCodeCache); if ((code != 11) && (code != 8) && (code != 15) && (code != 1)) encodeBuffer. encodeValue(GetULONG(buffer + 4, bigEndian_), 32, 16); if (code >= 18) encodeBuffer. encodeCachedValue(GetUINT (buffer + 8, bigEndian_), 16, serverCache_. errorMinorCache); encodeBuffer.encodeCachedValue(buffer[10], 8, serverCache_. errorMajorCache); if (code >= 18) { const unsigned char *nextSrc = buffer + 11; for (unsigned int i = 11; i < 32; i++) encodeBuffer.encodeValue(*nextSrc++, 8); } } break; case ButtonPress: case ButtonRelease: case KeyPress: case KeyRelease: case MotionNotify: case EnterNotify: case LeaveNotify: { unsigned char detail = buffer[1]; if (*buffer == MotionNotify) encodeBuffer.encodeValue((unsigned int) detail, 1); else if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) encodeBuffer.encodeValue((unsigned int) detail, 3); else if (*buffer == KeyRelease) { if (detail == serverCache_.keyPressLastKey) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); encodeBuffer. encodeValue((unsigned int) detail, 8); } } else if ((*buffer == ButtonPress) || (*buffer == ButtonRelease)) encodeBuffer.encodeCachedValue(detail, 8, serverCache_. buttonCache); else encodeBuffer.encodeValue((unsigned int) detail, 8); unsigned int timestamp = GetULONG(buffer + 4, bigEndian_); unsigned int timestampDiff = timestamp - serverCache_.lastTimestamp; serverCache_.lastTimestamp = timestamp; encodeBuffer.encodeCachedValue(timestampDiff, 32, serverCache_. motionNotifyTimestampCache, 9); int skipRest = 0; if (*buffer == KeyRelease) { skipRest = 1; for (unsigned int i = 8; i < 31; i++) { if (buffer[i] != serverCache_.keyPressCache[i - 8]) { skipRest = 0; break; } } encodeBuffer.encodeValue(skipRest, 1); } if (!skipRest) { const unsigned char *nextSrc = buffer + 8; for (unsigned int i = 0; i < 3; i++) { encodeBuffer. encodeCachedValue(GetULONG (nextSrc, bigEndian_), 29, *serverCache_. motionNotifyWindowCache [i], 6); nextSrc += 4; } unsigned int rootX = GetUINT(buffer + 20, bigEndian_); unsigned int rootY = GetUINT(buffer + 22, bigEndian_); unsigned int eventX = GetUINT(buffer + 24, bigEndian_); unsigned int eventY = GetUINT(buffer + 26, bigEndian_); eventX -= rootX; eventY -= rootY; encodeBuffer.encodeCachedValue(rootX - serverCache_. motionNotifyLastRootX, 16, serverCache_. motionNotifyRootXCache, 6); serverCache_.motionNotifyLastRootX = rootX; encodeBuffer.encodeCachedValue(rootY - serverCache_. motionNotifyLastRootY, 16, serverCache_. motionNotifyRootYCache, 6); serverCache_.motionNotifyLastRootY = rootY; encodeBuffer.encodeCachedValue(eventX, 16, serverCache_. motionNotifyEventXCache, 6); encodeBuffer.encodeCachedValue(eventY, 16, serverCache_. motionNotifyEventYCache, 6); encodeBuffer. encodeCachedValue(GetUINT (buffer + 28, bigEndian_), 16, serverCache_. motionNotifyStateCache); if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) encodeBuffer. encodeValue((unsigned int) buffer[30], 2); else encodeBuffer. encodeValue((unsigned int) buffer[30], 1); if ((*buffer == EnterNotify) || (*buffer == LeaveNotify)) encodeBuffer. encodeValue((unsigned int) buffer[31], 2); else if (*buffer == KeyPress) { serverCache_.keyPressLastKey = detail; for (unsigned int i = 8; i < 31; i++) { serverCache_.keyPressCache[i - 8] = buffer[i]; } } } } break; case ColormapNotify: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. colormapNotifyWindowCache, 8); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. colormapNotifyColormapCache, 8); encodeBuffer.encodeValue((unsigned int) buffer[12], 1); encodeBuffer.encodeValue((unsigned int) buffer[13], 1); } break; case ConfigureNotify: { const unsigned char *nextSrc = buffer + 4; for (unsigned int i = 0; i < 3; i++) { encodeBuffer. encodeCachedValue(GetULONG (nextSrc, bigEndian_), 29, *serverCache_. configureNotifyWindowCache [i], 9); nextSrc += 4; } for (unsigned int j = 0; j < 5; j++) { encodeBuffer. encodeCachedValue(GetUINT (nextSrc, bigEndian_), 16, *serverCache_. configureNotifyGeomCache[j], 8); nextSrc += 2; } encodeBuffer.encodeValue(*nextSrc, 1); } break; case CreateNotify: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. createNotifyWindowCache, 9); unsigned int window = GetULONG(buffer + 8, bigEndian_); encodeBuffer.encodeValue(window - serverCache_. createNotifyLastWindow, 29, 5); serverCache_.createNotifyLastWindow = window; const unsigned char *nextSrc = buffer + 12; for (unsigned int i = 0; i < 5; i++) { encodeBuffer. encodeValue(GetUINT(nextSrc, bigEndian_), 16, 9); nextSrc += 2; } encodeBuffer.encodeValue((unsigned int) *nextSrc, 1); } break; case Expose: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_.exposeWindowCache, 9); const unsigned char *nextSrc = buffer + 8; for (unsigned int i = 0; i < 5; i++) { encodeBuffer. encodeCachedValue(GetUINT (nextSrc, bigEndian_), 16, *serverCache_. exposeGeomCache[i], 6); nextSrc += 2; } } break; case FocusIn: case FocusOut: { encodeBuffer.encodeValue((unsigned int) buffer[1], 3); encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_.focusInWindowCache, 9); encodeBuffer.encodeValue((unsigned int) buffer[8], 2); } break; case KeymapNotify: { if (ServerCache::lastKeymap.compare(31, buffer + 1)) encodeBuffer.encodeValue(1, 1); else { encodeBuffer.encodeValue(0, 1); const unsigned char *nextSrc = buffer + 1; for (unsigned int i = 1; i < 32; i++) encodeBuffer. encodeValue((unsigned int) *nextSrc++, 8); } } break; case MapNotify: case UnmapNotify: case DestroyNotify: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. mapNotifyEventCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. mapNotifyWindowCache, 9); if ((*buffer == MapNotify) || (*buffer == UnmapNotify)) encodeBuffer. encodeValue((unsigned int) buffer[12], 1); } break; case NoExpose: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. noExposeDrawableCache, 9); encodeBuffer. encodeCachedValue(GetUINT(buffer + 8, bigEndian_), 16, serverCache_. noExposeMinorCache); encodeBuffer.encodeCachedValue(buffer[10], 8, serverCache_. noExposeMajorCache); } break; case PropertyNotify: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. propertyNotifyWindowCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. propertyNotifyAtomCache, 9); unsigned int timestamp = GetULONG(buffer + 12, bigEndian_); unsigned int timestampDiff = timestamp - serverCache_.lastTimestamp; serverCache_.lastTimestamp = timestamp; encodeBuffer.encodeValue(timestampDiff, 32, 9); encodeBuffer.encodeValue((unsigned int) buffer[16], 1); } break; case ReparentNotify: { const unsigned char *nextSrc = buffer + 4; for (unsigned int i = 0; i < 3; i++) { encodeBuffer. encodeCachedValue(GetULONG (nextSrc, bigEndian_), 29, serverCache_. reparentNotifyWindowCache, 9); nextSrc += 4; } encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 6); encodeBuffer. encodeValue(GetUINT(nextSrc + 2, bigEndian_), 16, 6); encodeBuffer.encodeValue((unsigned int) buffer[20], 1); } break; case SelectionClear: { unsigned int timestamp = GetULONG(buffer + 4, bigEndian_); unsigned int timestampDiff = timestamp - serverCache_.lastTimestamp; serverCache_.lastTimestamp = timestamp; encodeBuffer.encodeValue(timestampDiff, 32, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. selectionClearWindowCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 12, bigEndian_), 29, serverCache_. selectionClearAtomCache, 9); } break; case SelectionRequest: { unsigned int timestamp = GetULONG(buffer + 4, bigEndian_); unsigned int timestampDiff = timestamp - serverCache_.lastTimestamp; serverCache_.lastTimestamp = timestamp; encodeBuffer.encodeValue(timestampDiff, 32, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 8, bigEndian_), 29, serverCache_. selectionClearWindowCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 12, bigEndian_), 29, serverCache_. selectionClearWindowCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 16, bigEndian_), 29, serverCache_. selectionClearAtomCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 20, bigEndian_), 29, serverCache_. selectionClearAtomCache, 9); encodeBuffer. encodeCachedValue(GetULONG (buffer + 24, bigEndian_), 29, serverCache_. selectionClearAtomCache, 9); } break; case VisibilityNotify: { encodeBuffer. encodeCachedValue(GetULONG (buffer + 4, bigEndian_), 29, serverCache_. visibilityNotifyWindowCache, 9); encodeBuffer.encodeValue((unsigned int) buffer[8], 2); } break; default: { encodeBuffer.encodeValue(buffer[1], 8); for (unsigned int i = 4; i < size; i++) encodeBuffer.encodeValue((unsigned int) buffer[i], 8); } } stats_.add(*buffer, size << 3, encodeBuffer.getCumulativeBitsWritten()); } } } return 1; } int ServerChannel::doWrite(const unsigned char *message, unsigned int length) { writeBuffer_.reset(); // uncompress messages DecodeBuffer decodeBuffer(message, length); if (firstRequest_) { unsigned char *outputMessage = writeBuffer_.addMessage(length); unsigned char *nextDest = outputMessage; for (unsigned int i = 0; i < length; i++) { unsigned int nextByte; decodeBuffer.decodeValue(nextByte, 8); *nextDest++ = (unsigned char) nextByte; } if (*outputMessage == 0x42) setBigEndian(1); else setBigEndian(0); firstRequest_ = 0; } else { unsigned char opcode; while (decodeBuffer.decodeCachedValue(opcode, 8, clientCache_. opcodeCache[clientCache_. lastOpcode], 8, 1)) { clientCache_.lastOpcode = opcode; clientCache_.lastRequestSequenceNum++; unsigned char *outputMessage; unsigned int outputLength; unsigned int value; // general-purpose temp variable for decoding ints unsigned char cValue; // general-purpose temp variable for decoding chars switch (opcode) { case X_AllocColor: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.colormapCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; unsigned int colorData[3]; for (unsigned int i = 0; i < 3; i++) { decodeBuffer.decodeCachedValue(value, 16, *(clientCache_. allocColorRGBCache [i]), 4); PutUINT(value, nextDest, bigEndian_); colorData[i] = value; nextDest += 2; } sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode, colorData[0], colorData[1], colorData[2]); } break; case X_ChangeProperty: { unsigned char format; decodeBuffer.decodeCachedValue(format, 8, clientCache_. changePropertyFormatCache); unsigned int dataLength; decodeBuffer.decodeValue(dataLength, 32, 6); outputLength = 24 + RoundUp4(dataLength * (format >> 3)); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 2); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_. changePropertyPropertyCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_. changePropertyTypeCache, 9); PutULONG(value, outputMessage + 12, bigEndian_); outputMessage[16] = format; PutULONG(dataLength, outputMessage + 20, bigEndian_); unsigned char *nextDest = outputMessage + 24; if (format == 8) { clientCache_.changePropertyTextCompressor.reset(); for (unsigned int i = 0; i < dataLength; i++) *nextDest++ = clientCache_.changePropertyTextCompressor. decodeChar(decodeBuffer); } else if (format == 32) { for (unsigned int i = 0; i < dataLength; i++) { decodeBuffer.decodeCachedValue(value, 32, clientCache_. changePropertyData32Cache); PutULONG(value, nextDest, bigEndian_); nextDest += 4; } } else { for (unsigned int i = 0; i < dataLength; i++) { decodeBuffer.decodeValue(value, 16); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } } } break; case X_ChangeWindowAttributes: { unsigned int numAttrs; decodeBuffer.decodeValue(numAttrs, 4); outputLength = 12 + (numAttrs << 2); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned int bitmask; decodeBuffer.decodeCachedValue(bitmask, 15, clientCache_. createWindowBitmaskCache); PutULONG(bitmask, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; unsigned int mask = 0x1; for (unsigned int i = 0; i < 15; i++) { if (bitmask & mask) { decodeBuffer.decodeCachedValue(value, 32, *clientCache_. createWindowAttrCache [i]); PutULONG(value, nextDest, bigEndian_); nextDest += 4; } mask <<= 1; } } break; case X_ClearArea: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 1); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; for (unsigned int i = 0; i < 4; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. clearAreaGeomCache[i], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } } break; case X_CloseFont: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 29, 5); clientCache_.lastFont += value; clientCache_.lastFont &= 0x1fffffff; PutULONG(clientCache_.lastFont, outputMessage + 4, bigEndian_); } break; case X_ConfigureWindow: { outputLength = 12; outputMessage = writeBuffer_.addMessage(outputLength); writeBuffer_.registerPointer(&outputMessage); decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned int bitmask; decodeBuffer.decodeCachedValue(bitmask, 7, clientCache_. configureWindowBitmaskCache); PutUINT(bitmask, outputMessage + 8, bigEndian_); unsigned int mask = 0x1; for (unsigned int i = 0; i < 7; i++) { if (bitmask & mask) { unsigned char *nextDest = writeBuffer_.addMessage(4); outputLength += 4; decodeBuffer.decodeCachedValue(value, CONFIGUREWINDOW_FIELD_WIDTH [i], *clientCache_. configureWindowAttrCache [i], 8); PutULONG(value, nextDest, bigEndian_); nextDest += 4; } mask <<= 1; } writeBuffer_.unregisterPointer(); } break; case X_ConvertSelection: { outputLength = 24; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_. convertSelectionRequestorCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; for (unsigned int i = 0; i < 3; i++) { decodeBuffer.decodeCachedValue(value, 29, *(clientCache_. convertSelectionAtomCache [i]), 9); PutULONG(value, nextDest, bigEndian_); nextDest += 4; } decodeBuffer.decodeValue(value, 32, 4); clientCache_.convertSelectionLastTimestamp += value; PutULONG(clientCache_.convertSelectionLastTimestamp, nextDest, bigEndian_); } break; case X_CopyArea: { outputLength = 28; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 12, bigEndian_); unsigned char *nextDest = outputMessage + 16; for (unsigned int i = 0; i < 6; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. copyAreaGeomCache[i], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } } break; case X_CopyGC: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 23, clientCache_. createGCBitmaskCache); PutULONG(value, outputMessage + 12, bigEndian_); } break; case X_CopyPlane: { outputLength = 32; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 12, bigEndian_); unsigned char *nextDest = outputMessage + 16; for (unsigned int i = 0; i < 6; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. copyPlaneGeomCache[i], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } decodeBuffer.decodeCachedValue(value, 32, clientCache_. copyPlaneBitPlaneCache, 10); PutULONG(value, outputMessage + 28, bigEndian_); } break; case X_CreateGC: case X_ChangeGC: { outputLength = 12; if (opcode == X_CreateGC) outputLength += 4; outputMessage = writeBuffer_.addMessage(outputLength); writeBuffer_.registerPointer(&outputMessage); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned int offset = 8; if (opcode == X_CreateGC) { decodeBuffer.decodeCachedValue(value, 29, clientCache_. drawableCache, 9); PutULONG(value, outputMessage + offset, bigEndian_); offset += 4; } unsigned int bitmask; decodeBuffer.decodeCachedValue(bitmask, 23, clientCache_. createGCBitmaskCache); PutULONG(bitmask, outputMessage + offset, bigEndian_); unsigned int mask = 0x1; for (unsigned int i = 0; i < 23; i++) { if (bitmask & mask) { unsigned char *nextDest = writeBuffer_.addMessage(4); outputLength += 4; unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i]; if (fieldWidth <= 4) decodeBuffer.decodeValue(value, fieldWidth); else decodeBuffer.decodeCachedValue(value, fieldWidth, *clientCache_. createGCAttrCache [i]); PutULONG(value, nextDest, bigEndian_); } mask <<= 1; } writeBuffer_.unregisterPointer(); } break; case X_CreatePixmap: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(cValue, 8, clientCache_.depthCache); outputMessage[1] = cValue; decodeBuffer.decodeValue(value, 1); if (!value) { decodeBuffer.decodeValue(value, 29, 4); clientCache_.createPixmapLastPixmap += value; clientCache_.createPixmapLastPixmap &= 0x1fffffff; } PutULONG(clientCache_.createPixmapLastPixmap, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. createPixmapXCache, 8); PutUINT(value, outputMessage + 12, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. createPixmapYCache, 8); PutUINT(value, outputMessage + 14, bigEndian_); } break; case X_CreateWindow: { outputLength = 32; outputMessage = writeBuffer_.addMessage(outputLength); writeBuffer_.registerPointer(&outputMessage); decodeBuffer.decodeCachedValue(cValue, 8, clientCache_.depthCache); outputMessage[1] = cValue; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 12; unsigned int i; for (i = 0; i < 6; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. createWindowGeomCache [i], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } decodeBuffer.decodeCachedValue(value, 29, clientCache_.visualCache); PutULONG(value, outputMessage + 24, bigEndian_); unsigned int bitmask; decodeBuffer.decodeCachedValue(bitmask, 15, clientCache_. createWindowBitmaskCache); unsigned int newbitmask = bitmask; int addBackingStore = 0; if ((wantBackingStore != NotUseful) && !(bitmask & CWBackingStore)) { addBackingStore = 1; newbitmask |= CWBackingStore; } PutULONG(newbitmask, outputMessage + 28, bigEndian_); unsigned int mask = 0x1; for (i = 0; i < 15; i++) { if (bitmask & mask) { nextDest = writeBuffer_.addMessage(4); outputLength += 4; decodeBuffer.decodeCachedValue(value, 32, *clientCache_. createWindowAttrCache [i]); PutULONG(value, nextDest, bigEndian_); } else if (mask == CWBackingStore && addBackingStore) { nextDest = writeBuffer_.addMessage(4); outputLength += 4; PutULONG(wantBackingStore, nextDest, bigEndian_); } mask <<= 1; } writeBuffer_.unregisterPointer(); } break; case X_DeleteProperty: { outputLength = 12; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeValue(value, 29, 9); PutULONG(value, outputMessage + 8, bigEndian_); } break; case X_FillPoly: { unsigned int numPoints; decodeBuffer.decodeCachedValue(numPoints, 14, clientCache_. fillPolyNumPointsCache, 4); outputLength = 16 + (numPoints << 2); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 2); outputMessage[12] = (unsigned char) value; unsigned int relativeCoordMode; decodeBuffer.decodeValue(relativeCoordMode, 1); outputMessage[13] = (unsigned char) relativeCoordMode; unsigned char *nextDest = outputMessage + 16; unsigned int pointIndex = 0; for (unsigned int i = 0; i < numPoints; i++) { if (relativeCoordMode) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. fillPolyXRelCache [pointIndex], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. fillPolyYRelCache [pointIndex], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } else { unsigned int x, y; decodeBuffer.decodeValue(value, 1); if (value) { decodeBuffer.decodeValue(value, 3); x = clientCache_.fillPolyRecentX[value]; y = clientCache_.fillPolyRecentY[value]; } else { decodeBuffer.decodeCachedValue(x, 16, *clientCache_. fillPolyXAbsCache [pointIndex], 8); decodeBuffer.decodeCachedValue(y, 16, *clientCache_. fillPolyYAbsCache [pointIndex], 8); clientCache_.fillPolyRecentX[clientCache_. fillPolyIndex] = x; clientCache_.fillPolyRecentY[clientCache_. fillPolyIndex] = y; clientCache_.fillPolyIndex++; if (clientCache_.fillPolyIndex == 8) clientCache_.fillPolyIndex = 0; } PutUINT(x, nextDest, bigEndian_); nextDest += 2; PutUINT(y, nextDest, bigEndian_); nextDest += 2; } if (pointIndex + 1 < FILL_POLY_MAX_POINTS) pointIndex++; } } break; case X_FreeColors: { unsigned int numPixels; decodeBuffer.decodeValue(numPixels, 16, 4); outputLength = 12 + (numPixels << 2); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.colormapCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeValue(value, 32, 4); PutULONG(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; while (numPixels) { decodeBuffer.decodeValue(value, 32, 8); PutULONG(value, nextDest, bigEndian_); nextDest += 4; numPixels--; } } break; case X_FreeCursor: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.cursorCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); } break; case X_FreeGC: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); } break; case X_FreePixmap: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 1); if (!value) { decodeBuffer.decodeValue(value, 29, 4); clientCache_.createPixmapLastPixmap += value; clientCache_.createPixmapLastPixmap &= 0x1fffffff; } PutULONG(clientCache_.createPixmapLastPixmap, outputMessage + 4, bigEndian_); } break; case X_GetAtomName: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 29, 9); PutULONG(value, outputMessage + 4, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GetGeometry: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GetInputFocus: case X_GetModifierMapping: { outputLength = 4; outputMessage = writeBuffer_.addMessage(outputLength); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GetKeyboardMapping: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 8); outputMessage[4] = value; decodeBuffer.decodeValue(value, 8); outputMessage[5] = value; sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GetProperty: { outputLength = 24; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 1); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned int property; decodeBuffer.decodeValue(property, 29, 9); PutULONG(property, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 29, 9); PutULONG(value, outputMessage + 12, bigEndian_); decodeBuffer.decodeValue(value, 32, 2); PutULONG(value, outputMessage + 16, bigEndian_); decodeBuffer.decodeValue(value, 32, 8); PutULONG(value, outputMessage + 20, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode, property); } break; case X_GetSelectionOwner: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_. getSelectionOwnerSelectionCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GrabButton: case X_GrabPointer: { outputLength = 24; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 1); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. grabButtonEventMaskCache); PutUINT(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 1); outputMessage[10] = (unsigned char) value; decodeBuffer.decodeValue(value, 1); outputMessage[11] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_. grabButtonConfineCache, 9); PutULONG(value, outputMessage + 12, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.cursorCache, 9); PutULONG(value, outputMessage + 16, bigEndian_); if (opcode == X_GrabButton) { decodeBuffer.decodeCachedValue(cValue, 8, clientCache_. grabButtonButtonCache); outputMessage[20] = cValue; decodeBuffer.decodeCachedValue(value, 16, clientCache_. grabButtonModifierCache); PutUINT(value, outputMessage + 22, bigEndian_); } else { decodeBuffer.decodeValue(value, 32, 4); clientCache_.grabKeyboardLastTimestamp += value; PutULONG(clientCache_.grabKeyboardLastTimestamp, outputMessage + 20, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } } break; case X_GrabKeyboard: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 1); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeValue(value, 32, 4); clientCache_.grabKeyboardLastTimestamp += value; PutULONG(clientCache_.grabKeyboardLastTimestamp, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 1); outputMessage[12] = (unsigned char) value; decodeBuffer.decodeValue(value, 1); outputMessage[13] = (unsigned char) value; sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_GrabServer: case X_UngrabServer: case X_NoOperation: { outputLength = 4; outputMessage = writeBuffer_.addMessage(outputLength); } break; case X_ImageText8: { unsigned int textLength; decodeBuffer.decodeValue(textLength, 8); outputLength = 16 + RoundUp4(textLength); outputMessage = writeBuffer_.addMessage(outputLength); outputMessage[1] = (unsigned char) textLength; decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. imageText8CacheX, 8); clientCache_.imageText8LastX += value; clientCache_.imageText8LastX &= 0xffff; PutUINT(clientCache_.imageText8LastX, outputMessage + 12, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. imageText8CacheY, 8); clientCache_.imageText8LastY += value; clientCache_.imageText8LastY &= 0xffff; PutUINT(clientCache_.imageText8LastY, outputMessage + 14, bigEndian_); unsigned char *nextDest = outputMessage + 16; clientCache_.imageText8TextCompressor.reset(); while (textLength) { *nextDest++ = clientCache_.imageText8TextCompressor. decodeChar(decodeBuffer); textLength--; } } break; case X_InternAtom: { unsigned int nameLength; decodeBuffer.decodeValue(nameLength, 16, 6); outputLength = RoundUp4(nameLength) + 8; outputMessage = writeBuffer_.addMessage(outputLength); PutUINT(nameLength, outputMessage + 4, bigEndian_); decodeBuffer.decodeValue(value, 1); outputMessage[1] = (unsigned char) value; unsigned char *nextDest = outputMessage + 8; clientCache_.internAtomTextCompressor.reset(); for (unsigned int i = 0; i < nameLength; i++) *nextDest++ = clientCache_.internAtomTextCompressor. decodeChar(decodeBuffer); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_ListExtensions: { outputLength = 4; outputMessage = writeBuffer_.addMessage(outputLength); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_ListFonts: { unsigned int textLength; decodeBuffer.decodeValue(textLength, 16, 6); outputLength = 8 + RoundUp4(textLength); outputMessage = writeBuffer_.addMessage(outputLength); PutUINT(textLength, outputMessage + 6, bigEndian_); decodeBuffer.decodeValue(value, 16, 6); PutUINT(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; clientCache_.polyText8TextCompressor.reset(); for (unsigned int i = 0; i < textLength; i++) *nextDest++ = clientCache_.polyText8TextCompressor. decodeChar(decodeBuffer); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_LookupColor: case X_AllocNamedColor: { unsigned int textLength; decodeBuffer.decodeValue(textLength, 16, 6); outputLength = 12 + RoundUp4(textLength); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.colormapCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); PutUINT(textLength, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; clientCache_.polyText8TextCompressor.reset(); for (unsigned int i = 0; i < textLength; i++) *nextDest++ = clientCache_.polyText8TextCompressor. decodeChar(decodeBuffer); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_MapWindow: case X_UnmapWindow: case X_MapSubwindows: case X_GetWindowAttributes: case X_DestroyWindow: case X_DestroySubwindows: case X_QueryPointer: case X_QueryTree: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.windowCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); if ((opcode == X_QueryPointer) || (opcode == X_GetWindowAttributes) || (opcode == X_QueryTree)) sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_OpenFont: { unsigned int nameLength; decodeBuffer.decodeValue(nameLength, 16, 7); outputLength = RoundUp4(12 + nameLength); outputMessage = writeBuffer_.addMessage(outputLength); PutUINT(nameLength, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 29, 5); clientCache_.lastFont += value; clientCache_.lastFont &= 0x1fffffff; PutULONG(clientCache_.lastFont, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 12; clientCache_.openFontTextCompressor.reset(); for (; nameLength; nameLength--) *nextDest++ = clientCache_.openFontTextCompressor. decodeChar(decodeBuffer); } break; case X_PolyFillRectangle: { outputLength = 12; outputMessage = writeBuffer_.addMessage(outputLength); writeBuffer_.registerPointer(&outputMessage); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned int index = 0; unsigned int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0; unsigned int numRectangles = 0; for (;;) { outputLength += 8; writeBuffer_.addMessage(8); unsigned char *nextDest = outputMessage + 12 + (numRectangles << 3); numRectangles++; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyFillRectangleCacheX [index], 8); value += lastX; PutUINT(value, nextDest, bigEndian_); lastX = value; nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyFillRectangleCacheY [index], 8); value += lastY; PutUINT(value, nextDest, bigEndian_); lastY = value; nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyFillRectangleCacheWidth [index], 8); value += lastWidth; PutUINT(value, nextDest, bigEndian_); lastWidth = value; nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyFillRectangleCacheHeight [index], 8); value += lastHeight; PutUINT(value, nextDest, bigEndian_); lastHeight = value; nextDest += 2; index = 1; decodeBuffer.decodeValue(value, 1); if (!value) break; } writeBuffer_.unregisterPointer(); } break; case X_PolyPoint: { unsigned int numPoints; decodeBuffer.decodeValue(numPoints, 16, 4); outputLength = (numPoints << 2) + 12; outputMessage = writeBuffer_.addMessage(outputLength); unsigned int relativeCoordMode; decodeBuffer.decodeValue(relativeCoordMode, 1); outputMessage[1] = (unsigned char) relativeCoordMode; decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; unsigned int index = 0; unsigned int lastX = 0, lastY = 0; for (unsigned int i = 0; i < numPoints; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyPointCacheX[index], 8); lastX += value; PutUINT(lastX, nextDest, bigEndian_); nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyPointCacheY[index], 8); lastY += value; PutUINT(lastY, nextDest, bigEndian_); nextDest += 2; index = 1; } } break; case X_PolyLine: { unsigned int numPoints; decodeBuffer.decodeValue(numPoints, 16, 4); outputLength = (numPoints << 2) + 12; outputMessage = writeBuffer_.addMessage(outputLength); unsigned int relativeCoordMode; decodeBuffer.decodeValue(relativeCoordMode, 1); outputMessage[1] = (unsigned char) relativeCoordMode; decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; unsigned int index = 0; unsigned int lastX = 0, lastY = 0; for (unsigned int i = 0; i < numPoints; i++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyLineCacheX[index], 8); lastX += value; PutUINT(lastX, nextDest, bigEndian_); nextDest += 2; decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyLineCacheY[index], 8); lastY += value; PutUINT(lastY, nextDest, bigEndian_); nextDest += 2; index = 1; } } break; case X_PolyRectangle: { unsigned int numRectangles; decodeBuffer.decodeValue(numRectangles, 16, 3); outputLength = (numRectangles << 3) + 12; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; for (unsigned int i = 0; i < numRectangles; i++) for (unsigned int k = 0; k < 4; k++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. polyRectangleGeomCache [k], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } } break; case X_PolySegment: { unsigned int numSegments; decodeBuffer.decodeValue(numSegments, 16, 4); outputLength = (numSegments << 3) + 12; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; for (numSegments *= 2; numSegments; numSegments--) { unsigned int index; decodeBuffer.decodeValue(index, 1); unsigned int x; decodeBuffer.decodeCachedValue(x, 16, clientCache_. polySegmentCacheX, 6); x += clientCache_.polySegmentLastX[index]; PutUINT(x, nextDest, bigEndian_); nextDest += 2; unsigned int y; decodeBuffer.decodeCachedValue(y, 16, clientCache_. polySegmentCacheY, 6); y += clientCache_.polySegmentLastY[index]; PutUINT(y, nextDest, bigEndian_); nextDest += 2; clientCache_.polySegmentLastX[clientCache_. polySegmentCacheIndex] = x; clientCache_.polySegmentLastY[clientCache_. polySegmentCacheIndex] = y; if (clientCache_.polySegmentCacheIndex == 1) clientCache_.polySegmentCacheIndex = 0; else clientCache_.polySegmentCacheIndex = 1; } } break; case X_PolyText8: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. polyText8CacheX, 8); clientCache_.polyText8LastX += value; clientCache_.polyText8LastX &= 0xffff; PutUINT(clientCache_.polyText8LastX, outputMessage + 12, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. polyText8CacheY, 8); clientCache_.polyText8LastY += value; clientCache_.polyText8LastY &= 0xffff; PutUINT(clientCache_.polyText8LastY, outputMessage + 14, bigEndian_); unsigned int addedLength = 0; writeBuffer_.registerPointer(&outputMessage); for (;;) { decodeBuffer.decodeValue(value, 1); if (!value) break; unsigned int textLength; decodeBuffer.decodeValue(textLength, 8); if (textLength == 255) { addedLength += 5; unsigned char *nextSegment = writeBuffer_.addMessage(5); *nextSegment = (unsigned char) textLength; decodeBuffer.decodeCachedValue(value, 29, clientCache_. polyText8FontCache); PutULONG(value, nextSegment + 1, 1); } else { addedLength += (textLength + 2); unsigned char *nextSegment = writeBuffer_.addMessage(textLength + 2); *nextSegment = (unsigned char) textLength; unsigned char *nextDest = nextSegment + 1; decodeBuffer.decodeCachedValue(cValue, 8, clientCache_. polyText8DeltaCache); *nextDest++ = cValue; clientCache_.polyText8TextCompressor.reset(); while (textLength) { *nextDest++ = clientCache_.polyText8TextCompressor. decodeChar(decodeBuffer); textLength--; } } } outputLength += addedLength; unsigned int mod4 = (addedLength & 0x3); if (mod4) { unsigned int extra = 4 - mod4; unsigned char *nextDest = writeBuffer_.addMessage(extra); for (unsigned int i = 0; i < extra; i++) *nextDest++ = 0; outputLength += extra; } writeBuffer_.unregisterPointer(); } break; case X_PutImage: { decodeBuffer.decodeValue(value, 16, 8); outputLength = (value << 2); outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 2); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); unsigned int width; decodeBuffer.decodeCachedValue(width, 16, clientCache_. putImageWidthCache, 8); PutUINT(width, outputMessage + 12, bigEndian_); unsigned int height; decodeBuffer.decodeCachedValue(height, 16, clientCache_. putImageHeightCache, 8); PutUINT(height, outputMessage + 14, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. putImageXCache, 8); clientCache_.putImageLastX += value; clientCache_.putImageLastX &= 0xffff; PutUINT(clientCache_.putImageLastX, outputMessage + 16, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. putImageYCache, 8); clientCache_.putImageLastY += value; clientCache_.putImageLastY &= 0xffff; PutUINT(clientCache_.putImageLastY, outputMessage + 18, bigEndian_); decodeBuffer.decodeCachedValue(cValue, 8, clientCache_. putImageOffsetCache); outputMessage[20] = cValue; decodeBuffer.decodeCachedValue(cValue, 8, clientCache_.depthCache); outputMessage[21] = cValue; unsigned char *nextDest = outputMessage + 24; decodeBuffer.decodeValue(value, COMPRESSION_TYPE_BITS); CompressionType compressionType = (CompressionType) value; if (decompresser && compressionType != NO_STREAM_COMPRESSION) { decompresser->decompressBuffer(compressionType, nextDest, decodeBuffer); } else if ((outputMessage[1] == 0) && (height <= 32) && (width > height * PUT_IMAGE_MIN_ASPECT_RATIO)) { // bitmap that probably contains text; encode using a variant of // text-compression algorithm unsigned int widthInBits = ((width / scanlinePad_) * scanlinePad_); if (widthInBits < width) widthInBits += scanlinePad_; unsigned int widthInBytes = (widthInBits >> 3); unsigned char *nextDest = outputMessage + 24; memset(nextDest, 0, outputLength - 24); unsigned char destMask = 0x80; clientCache_.putImageLastPixels.reset(); for (unsigned int xCoord = 0; xCoord < width; xCoord++) { unsigned int modelNum = clientCache_.putImageLastPixels.getValue(); unsigned int columnValue; decodeBuffer.decodeCachedValue(columnValue, height, clientCache_. putImagePixelCache [modelNum % PUT_IMAGE_PIXEL_CACHE_SIZE], clientCache_. columnPixel0Coder, clientCache_. columnPixel1Coder); unsigned char *next = nextDest; unsigned int mask = (1 << (height - 1)); for (unsigned int h = 0; h < height; h++) { if (columnValue & mask) *next |= destMask; next += widthInBytes; mask >>= 1; } destMask >>= 1; if (destMask == 0) { destMask = 0x80; nextDest++; } clientCache_.putImageLastPixels.add(columnValue); } if ((imageByteOrder_ == 0) && (bitmapBitOrder_ == 0)) { unsigned char *next = outputMessage + 24; for (unsigned int i = 24; i < outputLength; i++) { *next = REVERSED_BYTE[*next]; next++; } } } else if (outputMessage[1] == 0) { // bitmap--use "Modified-Modified-Read" FAX coding if (width + 2 > clientCache_.putImageLineSize) { delete[]clientCache_.putImageReferenceLine; delete[]clientCache_.putImageCodingLine; clientCache_.putImageLineSize = width + 2; clientCache_.putImageReferenceLine = new unsigned int[width + 2]; clientCache_.putImageCodingLine = new unsigned int[width + 2]; } unsigned int widthInBits = ((width / scanlinePad_) * scanlinePad_); if (widthInBits < width) widthInBits += scanlinePad_; unsigned int widthInBytes = (widthInBits >> 3); unsigned int lastPixelValue = 0; for (unsigned int h = 0; h < height; h++) { unsigned int codingLineLength = 0; unsigned char *nextDest = outputMessage + 24 + h * widthInBytes; *nextDest = 0; unsigned char destMask = 0x80; if (h == 0) { unsigned int pixelValue; decodeBuffer.decodeValue(pixelValue, 1); for (unsigned int xCoord = 0; xCoord < width;) { if (pixelValue) { if (pixelValue != lastPixelValue) clientCache_. putImageCodingLine [codingLineLength++] = xCoord; unsigned int runLength = clientCache_.putImagePixel1Coder. decode(decodeBuffer); while (runLength--) { *nextDest |= destMask; destMask >>= 1; if (destMask == 0) { destMask = 0x80; nextDest++; if (xCoord + 1 < width) *nextDest = 0; } xCoord++; } pixelValue = 0; lastPixelValue = 1; } else { if (pixelValue != lastPixelValue) clientCache_. putImageCodingLine [codingLineLength++] = xCoord; unsigned int runLength = clientCache_.putImagePixel0Coder. decode(decodeBuffer); while (runLength--) { destMask >>= 1; if (destMask == 0) { destMask = 0x80; nextDest++; if (xCoord + 1 < width) *nextDest = 0; } xCoord++; } pixelValue = 1; lastPixelValue = 0; } } clientCache_. putImageCodingLine[codingLineLength++] = width; } else { unsigned int lastX = 0; unsigned int nextReferenceIndex = 0; while (lastX < width) { ScanlineDiff diffCode = (ScanlineDiff) clientCache_. putImageDiffCoder. decode(decodeBuffer); switch (diffCode) { case SD_VERTICAL_0: { lastX = clientCache_. putImageCodingLine [codingLineLength++] = clientCache_. putImageReferenceLine [nextReferenceIndex++]; } break; case SD_VERTICAL_PLUS_1: { lastX = clientCache_. putImageCodingLine [codingLineLength++] = clientCache_. putImageReferenceLine [nextReferenceIndex++] + 1; } break; case SD_VERTICAL_PLUS_2: { lastX = clientCache_. putImageCodingLine [codingLineLength++] = clientCache_. putImageReferenceLine [nextReferenceIndex++] + 2; } break; case SD_VERTICAL_MINUS_1: { lastX = clientCache_. putImageCodingLine [codingLineLength++] = clientCache_. putImageReferenceLine [nextReferenceIndex++] - 1; } break; case SD_VERTICAL_MINUS_2: { lastX = clientCache_. putImageCodingLine [codingLineLength++] = clientCache_. putImageReferenceLine [nextReferenceIndex++] - 2; } break; case SD_PASS: { nextReferenceIndex += 2; } break; case SD_HORIZONTAL: { unsigned int diff; if (codingLineLength & 1) diff = clientCache_. putImagePixel0Coder. decode(decodeBuffer); else diff = clientCache_. putImagePixel1Coder. decode(decodeBuffer); lastX += diff; lastX &= 0xffff; clientCache_. putImageCodingLine [codingLineLength++] = lastX; if (codingLineLength & 1) diff = clientCache_. putImagePixel0Coder. decode(decodeBuffer); else diff = clientCache_. putImagePixel1Coder. decode(decodeBuffer); lastX += diff; lastX &= 0xffff; clientCache_. putImageCodingLine [codingLineLength++] = lastX; } default: { } } } } clientCache_. putImageCodingLine[codingLineLength++] = width; unsigned int pixelValue = 0; unsigned int lastPixelChange = 0; unsigned int *nextPixelChange = clientCache_.putImageCodingLine; for (unsigned int xCoord = 0; xCoord < width;) { unsigned int count = *nextPixelChange - lastPixelChange; lastPixelChange = *nextPixelChange++; for (; count; count--) { if (pixelValue) *nextDest |= destMask; destMask >>= 1; if (destMask == 0) { destMask = 0x80; nextDest++; if (xCoord + 1 < width) *nextDest = 0; } xCoord++; } if (pixelValue) pixelValue = 0; else pixelValue = 1; } unsigned int *tmp = clientCache_.putImageReferenceLine; clientCache_.putImageReferenceLine = clientCache_.putImageCodingLine; clientCache_.putImageCodingLine = tmp; } const unsigned char *end = outputMessage + outputLength; if ((imageByteOrder_ == 0) && (bitmapBitOrder_ == 0)) { for (unsigned char *next = outputMessage + 24; next < end; next++) *next = REVERSED_BYTE[*next]; } unsigned char *next = outputMessage + 24 + widthInBytes; const unsigned char *prev = outputMessage + 24; for (; next < end;) *next++ ^= *prev++; } else { // pixmap if (outputMessage[21] == 8) { for (unsigned int i = 24; i < outputLength; i++) { decodeBuffer.decodeCachedValue(cValue, 8, clientCache_. putImageByteCache, 4); *nextDest++ = cValue; } } else { for (unsigned int i = 24; i < outputLength; i++) { decodeBuffer.decodeValue(value, 8); *nextDest++ = (unsigned char) value; } } } } break; case X_QueryBestSize: { outputLength = 12; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 2); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.drawableCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeValue(value, 16, 8); PutUINT(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeValue(value, 16, 8); PutUINT(value, outputMessage + 10, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_QueryColors: { unsigned int numColors; decodeBuffer.decodeValue(numColors, 16, 5); outputLength = (numColors << 2) + 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_.colormapCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; unsigned int predictedPixel = clientCache_.queryColorsLastPixel; for (unsigned int i = 0; i < numColors; i++) { unsigned int pixel; decodeBuffer.decodeValue(value, 1); if (value) pixel = predictedPixel; else decodeBuffer.decodeValue(pixel, 32, 9); PutULONG(pixel, nextDest, bigEndian_); if (i == 0) clientCache_.queryColorsLastPixel = pixel; predictedPixel = pixel + 1; nextDest += 4; } sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_QueryExtension: { unsigned int nameLength; decodeBuffer.decodeValue(nameLength, 16, 6); outputLength = 8 + RoundUp4(nameLength); outputMessage = writeBuffer_.addMessage(outputLength); PutUINT(nameLength, outputMessage + 4, bigEndian_); unsigned char *nextDest = outputMessage + 8; for (unsigned int i = 0; i < nameLength; i++) { decodeBuffer.decodeValue(value, 8); *nextDest++ = (unsigned char) value; } unsigned int hideExtension = 0; if (!strncmp((char *) outputMessage + 8, "MIT-SHM", 7)) { *logofs << "hiding MIT-SHM!"; hideExtension = 1; } sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode, hideExtension); } break; case X_QueryFont: { outputLength = 8; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 29, 5); clientCache_.lastFont += value; clientCache_.lastFont &= 0x1fffffff; PutULONG(clientCache_.lastFont, outputMessage + 4, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; case X_SetClipRectangles: { unsigned int numRectangles; decodeBuffer.decodeValue(numRectangles, 13, 4); outputLength = (numRectangles << 3) + 12; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeValue(value, 2); outputMessage[1] = (unsigned char) value; decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. setClipRectanglesXCache, 8); PutUINT(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. setClipRectanglesYCache, 8); PutUINT(value, outputMessage + 10, bigEndian_); unsigned char *nextDest = outputMessage + 12; for (unsigned int i = 0; i < numRectangles; i++) { for (unsigned int k = 0; k < 4; k++) { decodeBuffer.decodeCachedValue(value, 16, *clientCache_. setClipRectanglesGeomCache [k], 8); PutUINT(value, nextDest, bigEndian_); nextDest += 2; } } } break; case X_SetDashes: { unsigned int numDashes; decodeBuffer.decodeCachedValue(numDashes, 16, clientCache_. setDashesLengthCache, 5); outputLength = 12 + RoundUp4(numDashes); outputMessage = writeBuffer_.addMessage(outputLength); PutUINT(numDashes, outputMessage + 10, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_.gcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. setDashesOffsetCache, 5); PutUINT(value, outputMessage + 8, bigEndian_); unsigned char *nextDest = outputMessage + 12; for (unsigned int i = 0; i < numDashes; i++) { decodeBuffer.decodeCachedValue(cValue, 8, clientCache_. setDashesDashCache_[i & 1], 5); *nextDest++ = cValue; } } break; case X_SetSelectionOwner: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_. setSelectionOwnerCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_. getSelectionOwnerSelectionCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 32, clientCache_. setSelectionOwnerTimestampCache, 9); PutULONG(value, outputMessage + 12, bigEndian_); } break; case X_TranslateCoords: { outputLength = 16; outputMessage = writeBuffer_.addMessage(outputLength); decodeBuffer.decodeCachedValue(value, 29, clientCache_. translateCoordsSrcCache, 9); PutULONG(value, outputMessage + 4, bigEndian_); decodeBuffer.decodeCachedValue(value, 29, clientCache_. translateCoordsDestCache, 9); PutULONG(value, outputMessage + 8, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. translateCoordsXCache, 8); PutUINT(value, outputMessage + 12, bigEndian_); decodeBuffer.decodeCachedValue(value, 16, clientCache_. translateCoordsYCache, 8); PutUINT(value, outputMessage + 14, bigEndian_); sequenceNumQueue_.push(clientCache_. lastRequestSequenceNum, opcode); } break; default: { unsigned int secondByte; decodeBuffer.decodeValue(secondByte, 8); decodeBuffer.decodeValue(outputLength, 16, 8); outputLength <<= 2; outputMessage = writeBuffer_.addMessage(outputLength); outputMessage[1] = (unsigned char) secondByte; unsigned char *nextDest = outputMessage + 4; for (unsigned int i = 4; i < outputLength; i++) { unsigned int nextByte; decodeBuffer.decodeValue(nextByte, 8); *nextDest++ = (unsigned char) nextByte; } } } *outputMessage = (unsigned char) opcode; PutUINT(outputLength >> 2, outputMessage + 2, bigEndian_); } } if (WriteAll(fd_, writeBuffer_.getData(), writeBuffer_.getLength()) < 0) return 0; else return 1; } void ServerChannel:: setBigEndian(int flag) { bigEndian_ = flag; readBuffer_.setBigEndian(flag); } void ServerChannel::encodeCharInfo_(const unsigned char *nextSrc, EncodeBuffer & encodeBuffer) { unsigned int value = GetUINT(nextSrc, bigEndian_) | (GetUINT(nextSrc + 10, bigEndian_) << 16); encodeBuffer.encodeCachedValue(value, 32, *serverCache_.queryFontCharInfoCache[0], 6); nextSrc += 2; for (unsigned int i = 1; i < 5; i++) { unsigned int value = GetUINT(nextSrc, bigEndian_); nextSrc += 2; encodeBuffer.encodeCachedValue(value, 16, *serverCache_. queryFontCharInfoCache[i], 6); } }