/** * Decompress bitmap data from packet and store in array of bytes * * @param width Width of bitmap * @param height Height of bitmap * @param size Size of compressed data in bytes * @param data Packet containing bitmap data * @param Bpp Bytes per-pixel for bitmap * @return Byte array of pixels containing decompressed bitmap data * @throws RdesktopException */ public static byte[] decompress( int width, int height, int size, RdpPacket_Localised data, int Bpp) throws RdesktopException { byte[] compressed_pixel = new byte[size]; data.copyToByteArray(compressed_pixel, 0, data.getPosition(), size); data.incrementPosition(size); int previous = 0, line = 0; int input = 0, output = 0, end = size; int opcode = 0, count = 0, offset = 0, x = width; int lastopcode = -1, fom_mask = 0; int code = 0, color1 = 0, color2 = 0; byte mixmask = 0; int mask = 0; int mix = 0xffffffff; boolean insertmix = false, bicolor = false, isfillormix = false; byte[] pixel = new byte[width * height]; while (input < end) { fom_mask = 0; code = (compressed_pixel[input++] & 0x000000ff); opcode = code >> 4; /* Handle different opcode forms */ switch (opcode) { case 0xc: case 0xd: case 0xe: opcode -= 6; count = code & 0xf; offset = 16; break; case 0xf: opcode = code & 0xf; if (opcode < 9) { count = (compressed_pixel[input++] & 0xff); count |= ((compressed_pixel[input++] & 0xff) << 8); } else { count = (opcode < 0xb) ? 8 : 1; } offset = 0; break; default: opcode >>= 1; count = code & 0x1f; offset = 32; break; } /* Handle strange cases for counts */ if (offset != 0) { isfillormix = ((opcode == 2) || (opcode == 7)); if (count == 0) { if (isfillormix) count = (compressed_pixel[input++] & 0x000000ff) + 1; else count = (compressed_pixel[input++] & 0x000000ff) + offset; } else if (isfillormix) { count <<= 3; } } switch (opcode) { case 0: /* Fill */ if ((lastopcode == opcode) && !((x == width) && (previous == 0))) insertmix = true; break; case 8: /* Bicolor */ // color1 = cvalx(compressed_pixel, input, Bpp); // // (compressed_pixel[input++]&0x000000ff); color1 = (compressed_pixel[input++] & 0x000000ff); // input += Bpp; case 3: /* Color */ // color2 = cvalx(compressed_pixel, input, Bpp); color2 = (compressed_pixel[input++] & 0x000000ff); // input += Bpp; break; case 6: /* SetMix/Mix */ case 7: /* SetMix/FillOrMix */ mix = compressed_pixel[input++]; // mix = cvalx(compressed_pixel, input, Bpp); // input += Bpp; opcode -= 5; break; case 9: /* FillOrMix_1 */ mask = 0x03; opcode = 0x02; fom_mask = 3; break; case 0x0a: /* FillOrMix_2 */ mask = 0x05; opcode = 0x02; fom_mask = 5; break; } lastopcode = opcode; mixmask = 0; /* Output body */ while (count > 0) { if (x >= width) { if (height <= 0) throw new RdesktopException("Decompressing bitmap failed! Height = " + height); x = 0; height--; previous = line; line = output + height * width; } switch (opcode) { case 0: /* Fill */ if (insertmix) { if (previous == 0) { pixel[line + x] = (byte) mix; } else { // setli(pixel, line, x, getli(pixel, previous, x, // Bpp) ^ mix, Bpp); pixel[line + x] = (byte) (pixel[previous + x] ^ (byte) mix); } insertmix = false; count--; x++; } if (previous == 0) { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, 0, Bpp); pixel[line + x] = 0; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, 0, Bpp); pixel[line + x] = 0; count--; x++; } } else { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, getli(pixel, previous, // x, Bpp), Bpp); pixel[line + x] = pixel[previous + x]; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, getli(pixel, previous, x, // Bpp), Bpp); pixel[line + x] = pixel[previous + x]; count--; x++; } } break; case 1: /* Mix */ if (previous == 0) { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, mix, Bpp); pixel[line + x] = (byte) mix; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, mix, Bpp); pixel[line + x] = (byte) mix; count--; x++; } } else { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { setli(pixel, line, x, getli(pixel, previous, x, 1) ^ mix, 1); // setli(pixel, line, x, 0, Bpp); count--; x++; } } while ((count > 0) && (x < width)) { setli(pixel, line, x, getli(pixel, previous, x, 1) ^ mix, 1); // setli(pixel, line, x, 0, Bpp); count--; x++; } } break; case 2: /* Fill or Mix */ if (previous == 0) { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { mixmask <<= 1; if (mixmask == 0) { mask = (fom_mask != 0) ? (byte) fom_mask : compressed_pixel[input++]; mixmask = 1; } if ((mask & mixmask) != 0) // setli(pixel, line, x, mix, Bpp); pixel[line + x] = (byte) mix; else // setli(pixel, line, x, 0, Bpp); pixel[line + x] = 0; count--; x++; } } while ((count > 0) && (x < width)) { mixmask <<= 1; if (mixmask == 0) { mask = (fom_mask != 0) ? (byte) fom_mask : compressed_pixel[input++]; mixmask = 1; } if ((mask & mixmask) != 0) // setli(pixel, line, x, mix, Bpp); pixel[line + x] = (byte) mix; else // setli(pixel, line, x, 0, Bpp); pixel[line + x] = 0; count--; x++; } } else { while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { mixmask <<= 1; if (mixmask == 0) { mask = (fom_mask != 0) ? (byte) fom_mask : compressed_pixel[input++]; mixmask = 1; } if ((mask & mixmask) != 0) // setli(pixel, line, x, getli(pixel, // previous, x, Bpp) // ^ mix, Bpp); pixel[line + x] = (byte) (pixel[previous + x] ^ (byte) mix); else // setli(pixel, line, x, getli(pixel, // previous, x, Bpp), Bpp); pixel[line + x] = pixel[previous + x]; count--; x++; } } while ((count > 0) && (x < width)) { mixmask <<= 1; if (mixmask == 0) { mask = (fom_mask != 0) ? (byte) fom_mask : compressed_pixel[input++]; mixmask = 1; } if ((mask & mixmask) != 0) // setli(pixel, line, x, getli(pixel, previous, // x, // Bpp) // ^ mix, Bpp); pixel[line + x] = (byte) (pixel[previous + x] ^ (byte) mix); else // setli(pixel, line, x, getli(pixel, previous, // x, // Bpp), Bpp); pixel[line + x] = pixel[previous + x]; count--; x++; } } break; case 3: /* Color */ while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, color2, Bpp); pixel[line + x] = (byte) color2; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, color2, Bpp); pixel[line + x] = (byte) color2; count--; x++; } break; case 4: /* Copy */ while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, cvalx(compressed_pixel, // input, Bpp), Bpp); pixel[line + x] = compressed_pixel[input++]; // input += Bpp; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, cvalx(compressed_pixel, input, // Bpp), Bpp); // input += Bpp; pixel[line + x] = compressed_pixel[input++]; count--; x++; } break; case 8: /* Bicolor */ while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { if (bicolor) { // setli(pixel, line, x, color2, Bpp); pixel[line + x] = (byte) color2; bicolor = false; } else { // setli(pixel, line, x, color1, Bpp); pixel[line + x] = (byte) color1; bicolor = true; count++; } count--; x++; } } while ((count > 0) && (x < width)) { if (bicolor) { // setli(pixel, line, x, color2, Bpp); pixel[line + x] = (byte) color2; bicolor = false; } else { // setli(pixel, line, x, color1, Bpp); pixel[line + x] = (byte) color1; bicolor = true; count++; } count--; x++; } break; case 0xd: /* White */ while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, 0xffffffff, Bpp); pixel[line + x] = (byte) 0xff; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, 0xffffffff, Bpp); pixel[line + x] = (byte) 0xff; count--; x++; } break; case 0xe: /* Black */ while (((count & ~0x7) != 0) && ((x + 8) < width)) { for (int i = 0; i < 8; i++) { // setli(pixel, line, x, 0, Bpp); pixel[line + x] = (byte) 0x00; count--; x++; } } while ((count > 0) && (x < width)) { // setli(pixel, line, x, 0, Bpp); pixel[line + x] = (byte) 0x00; count--; x++; } break; default: throw new RdesktopException("Unimplemented decompress opcode " + opcode); // ; } } } bmpCount++; return pixel; }