/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
package com.tigervnc.rfb;
import java.awt.image.*;
import java.nio.*;
import java.util.Arrays;
import com.tigervnc.rdr.*;
public class HextileDecoder extends Decoder {
public static final int hextileRaw = (1 << 0);
public static final int hextileBgSpecified = (1 << 1);
public static final int hextileFgSpecified = (1 << 2);
public static final int hextileAnySubrects = (1 << 3);
public static final int hextileSubrectsColoured = (1 << 4);
public HextileDecoder() { super(DecoderFlags.DecoderPlain); }
public void readRect(Rect r, InStream is,
ConnParams cp, OutStream os)
{
Rect t = new Rect();
int bytesPerPixel;
bytesPerPixel = cp.pf().bpp/8;
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
t.br.y = Math.min(r.br.y, t.tl.y + 16);
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
int tileType;
t.br.x = Math.min(r.br.x, t.tl.x + 16);
tileType = is.readU8() & 0xff;
os.writeU32(tileType);
if ((tileType & hextileRaw) != 0) {
os.copyBytes(is, t.area() * bytesPerPixel);
continue;
}
if ((tileType & hextileBgSpecified) != 0)
os.copyBytes(is, bytesPerPixel);
if ((tileType & hextileFgSpecified) != 0)
os.copyBytes(is, bytesPerPixel);
if ((tileType & hextileAnySubrects) != 0) {
int nSubrects;
nSubrects = is.readU8() & 0xff;
os.writeU32(nSubrects);
if ((tileType & hextileSubrectsColoured) != 0)
os.copyBytes(is, nSubrects * (bytesPerPixel + 2));
else
os.copyBytes(is, nSubrects * 2);
}
}
}
}
public void decodeRect(Rect r, Object buffer,
int buflen, ConnParams cp,
ModifiablePixelBuffer pb)
{
MemInStream is = new MemInStream((byte[])buffer, 0, buflen);
PixelFormat pf = cp.pf();
switch (pf.bpp) {
case 8: hextileDecode8(r, is, pf, pb); break;
case 16: hextileDecode16(r, is, pf, pb); break;
case 32: hextileDecode32(r, is, pf, pb); break;
}
}
private void hextileDecode8(Rect r, InStream is,
PixelFormat pf,
ModifiablePixelBuffer pb)
{
HEXTILE_DECODE(r, is, pf, pb);
}
private void hextileDecode16(Rect r, InStream is,
PixelFormat pf,
ModifiablePixelBuffer pb)
{
HEXTILE_DECODE(r, is, pf, pb);
}
private void hextileDecode32(Rect r, InStream is,
PixelFormat pf,
ModifiablePixelBuffer pb)
{
HEXTILE_DECODE(r, is, pf, pb);
}
private static ByteBuffer READ_PIXEL(InStream is, PixelFormat pf) {
ByteBuffer b = ByteBuffer.allocate(4);
switch (pf.bpp) {
case 8:
b.putInt(is.readOpaque8());
return ByteBuffer.allocate(1).put(b.get(3));
case 16:
b.putInt(is.readOpaque16());
return ByteBuffer.allocate(2).put(b.array(), 2, 2);
case 32:
default:
b.putInt(is.readOpaque32());
return b;
}
}
private void HEXTILE_DECODE(Rect r, InStream is,
PixelFormat pf,
ModifiablePixelBuffer pb)
{
Rect t = new Rect();
ByteBuffer bg = ByteBuffer.allocate(pf.bpp/8);
ByteBuffer fg = ByteBuffer.allocate(pf.bpp/8);
ByteBuffer buf = ByteBuffer.allocate(16 * 16 * 4);
for (t.tl.y = r.tl.y; t.tl.y < r.br.y; t.tl.y += 16) {
t.br.y = Math.min(r.br.y, t.tl.y + 16);
for (t.tl.x = r.tl.x; t.tl.x < r.br.x; t.tl.x += 16) {
t.br.x = Math.min(r.br.x, t.tl.x + 16);
int tileType = is.readU32();
if ((tileType & hextileRaw) != 0) {
is.readBytes(buf, t.area() * (pf.bpp/8));
pb.imageRect(pf, t, buf.array());
continue;
}
if ((tileType & hextileBgSpecified) != 0)
bg = READ_PIXEL(is, pf);
int len = t.area();
ByteBuffer ptr = buf.duplicate();
while (len-- > 0) ptr.put(bg.array());
if ((tileType & hextileFgSpecified) != 0)
fg = READ_PIXEL(is, pf);
if ((tileType & hextileAnySubrects) != 0) {
int nSubrects = is.readU32();
for (int i = 0; i < nSubrects; i++) {
if ((tileType & hextileSubrectsColoured) != 0)
fg = READ_PIXEL(is, pf);
int xy = is.readU8();
int wh = is.readU8();
int x = ((xy >> 4) & 15);
int y = (xy & 15);
int w = ((wh >> 4) & 15) + 1;
int h = (wh & 15) + 1;
ptr = buf.duplicate();
ptr.position((y * t.width() + x)*pf.bpp/8);
int rowAdd = (t.width() - w)*pf.bpp/8;
while (h-- > 0) {
len = w;
while (len-- > 0) ptr.put(fg.array());
ptr.position(ptr.position()+Math.min(rowAdd,ptr.remaining()));
}
}
}
pb.imageRect(pf, t, buf.array());
}
}
}
}