mirror of
https://github.com/yv1ing/ShotRDP.git
synced 2025-09-16 15:10:57 +08:00
1237 lines
26 KiB
Go
1237 lines
26 KiB
Go
package pdu
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
|
|
"ShotRDP/grdp/core"
|
|
"ShotRDP/grdp/glog"
|
|
)
|
|
|
|
type ControlFlag uint8
|
|
|
|
const (
|
|
TS_STANDARD = 0x01
|
|
TS_SECONDARY = 0x02
|
|
TS_BOUNDS = 0x04
|
|
TS_TYPE_CHANGE = 0x08
|
|
TS_DELTA_COORDINATES = 0x10
|
|
TS_ZERO_BOUNDS_DELTAS = 0x20
|
|
TS_ZERO_FIELD_BYTE_BIT0 = 0x40
|
|
TS_ZERO_FIELD_BYTE_BIT1 = 0x80
|
|
)
|
|
|
|
type PrimaryOrderType uint8
|
|
|
|
const (
|
|
ORDER_TYPE_DSTBLT = 0x00 //0
|
|
ORDER_TYPE_PATBLT = 0x01 //1
|
|
ORDER_TYPE_SCRBLT = 0x02 //2
|
|
//ORDER_TYPE_DRAWNINEGRID = 0x07 //7
|
|
//ORDER_TYPE_MULTI_DRAWNINEGRID = 0x08 //8
|
|
ORDER_TYPE_LINETO = 0x09 //9
|
|
ORDER_TYPE_OPAQUERECT = 0x0A //10
|
|
ORDER_TYPE_SAVEBITMAP = 0x0B //11
|
|
ORDER_TYPE_MEMBLT = 0x0D //13
|
|
ORDER_TYPE_MEM3BLT = 0x0E //14
|
|
//ORDER_TYPE_MULTIDSTBLT = 0x0F //15
|
|
//ORDER_TYPE_MULTIPATBLT = 0x10 //16
|
|
//ORDER_TYPE_MULTISCRBLT = 0x11 //17
|
|
//ORDER_TYPE_MULTIOPAQUERECT = 0x12 //18
|
|
//ORDER_TYPE_FAST_INDEX = 0x13 //19
|
|
ORDER_TYPE_POLYGON_SC = 0x14 //20
|
|
ORDER_TYPE_POLYGON_CB = 0x15 //21
|
|
ORDER_TYPE_POLYLINE = 0x16 //22
|
|
//ORDER_TYPE_FAST_GLYPH = 0x18 //24
|
|
ORDER_TYPE_ELLIPSE_SC = 0x19 //25
|
|
ORDER_TYPE_ELLIPSE_CB = 0x1A //26
|
|
ORDER_TYPE_TEXT2 = 0x1B //27
|
|
)
|
|
|
|
type SecondaryOrderType uint8
|
|
|
|
const (
|
|
ORDER_TYPE_BITMAP_UNCOMPRESSED = 0x00
|
|
ORDER_TYPE_CACHE_COLOR_TABLE = 0x01
|
|
ORDER_TYPE_CACHE_BITMAP_COMPRESSED = 0x02
|
|
ORDER_TYPE_CACHE_GLYPH = 0x03
|
|
ORDER_TYPE_BITMAP_UNCOMPRESSED_V2 = 0x04
|
|
ORDER_TYPE_BITMAP_COMPRESSED_V2 = 0x05
|
|
ORDER_TYPE_CACHE_BRUSH = 0x07
|
|
ORDER_TYPE_BITMAP_COMPRESSED_V3 = 0x08
|
|
)
|
|
|
|
func (s SecondaryOrderType) String() string {
|
|
name := "Unknown"
|
|
switch s {
|
|
case ORDER_TYPE_BITMAP_UNCOMPRESSED:
|
|
name = "Cache Bitmap"
|
|
case ORDER_TYPE_CACHE_COLOR_TABLE:
|
|
name = "Cache Color Table"
|
|
case ORDER_TYPE_CACHE_BITMAP_COMPRESSED:
|
|
name = "Cache Bitmap (Compressed)"
|
|
case ORDER_TYPE_CACHE_GLYPH:
|
|
name = "Cache Glyph"
|
|
case ORDER_TYPE_BITMAP_UNCOMPRESSED_V2:
|
|
name = "Cache Bitmap V2"
|
|
case ORDER_TYPE_BITMAP_COMPRESSED_V2:
|
|
name = "Cache Bitmap V2 (Compressed)"
|
|
case ORDER_TYPE_CACHE_BRUSH:
|
|
name = "Cache Brush"
|
|
case ORDER_TYPE_BITMAP_COMPRESSED_V3:
|
|
name = "Cache Bitmap V3"
|
|
}
|
|
return fmt.Sprintf("[0x%02d] %s", s, name)
|
|
}
|
|
|
|
/* Alternate Secondary Drawing Orders */
|
|
const (
|
|
ORDER_TYPE_SWITCH_SURFACE = 0x00
|
|
ORDER_TYPE_CREATE_OFFSCREEN_BITMAP = 0x01
|
|
ORDER_TYPE_STREAM_BITMAP_FIRST = 0x02
|
|
ORDER_TYPE_STREAM_BITMAP_NEXT = 0x03
|
|
ORDER_TYPE_CREATE_NINE_GRID_BITMAP = 0x04
|
|
ORDER_TYPE_GDIPLUS_FIRST = 0x05
|
|
ORDER_TYPE_GDIPLUS_NEXT = 0x06
|
|
ORDER_TYPE_GDIPLUS_END = 0x07
|
|
ORDER_TYPE_GDIPLUS_CACHE_FIRST = 0x08
|
|
ORDER_TYPE_GDIPLUS_CACHE_NEXT = 0x09
|
|
ORDER_TYPE_GDIPLUS_CACHE_END = 0x0A
|
|
ORDER_TYPE_WINDOW = 0x0B
|
|
ORDER_TYPE_COMPDESK_FIRST = 0x0C
|
|
ORDER_TYPE_FRAME_MARKER = 0x0D
|
|
)
|
|
|
|
const (
|
|
GLYPH_FRAGMENT_NOP = 0x00
|
|
GLYPH_FRAGMENT_USE = 0xFE
|
|
GLYPH_FRAGMENT_ADD = 0xFF
|
|
|
|
CBR2_HEIGHT_SAME_AS_WIDTH = 0x01
|
|
CBR2_PERSISTENT_KEY_PRESENT = 0x02
|
|
CBR2_NO_BITMAP_COMPRESSION_HDR = 0x08
|
|
CBR2_DO_NOT_CACHE = 0x10
|
|
)
|
|
|
|
const (
|
|
ORDER_PRIMARY = iota
|
|
ORDER_SECONDARY
|
|
ORDER_ALTSEC
|
|
)
|
|
|
|
type OrderPdu struct {
|
|
ControlFlags uint8
|
|
Type int
|
|
Altsec *Altsec
|
|
Primary *Primary
|
|
Secondary *Secondary
|
|
}
|
|
|
|
func (o *OrderPdu) HasBounds() bool {
|
|
return o.ControlFlags&TS_BOUNDS != 0
|
|
}
|
|
|
|
type Altsec struct {
|
|
}
|
|
|
|
type Secondary struct {
|
|
}
|
|
|
|
type Primary struct {
|
|
Bounds Bounds
|
|
Data PrimaryOrder
|
|
}
|
|
|
|
type FastPathOrdersPDU struct {
|
|
NumberOrders uint16
|
|
OrderPdus []OrderPdu
|
|
}
|
|
|
|
func (*FastPathOrdersPDU) FastPathUpdateType() uint8 {
|
|
return FASTPATH_UPDATETYPE_ORDERS
|
|
}
|
|
|
|
func (f *FastPathOrdersPDU) Unpack(r io.Reader) error {
|
|
f.NumberOrders, _ = core.ReadUint16LE(r)
|
|
//glog.Info("NumberOrders:", f.NumberOrders)
|
|
for i := 0; i < int(f.NumberOrders); i++ {
|
|
var o OrderPdu
|
|
o.ControlFlags, _ = core.ReadUInt8(r)
|
|
if o.ControlFlags&TS_STANDARD == 0 {
|
|
//glog.Info("Altsec order")
|
|
o.processAltsecOrder(r)
|
|
o.Type = ORDER_ALTSEC
|
|
//return errors.New("Not support")
|
|
} else if o.ControlFlags&TS_SECONDARY != 0 {
|
|
//glog.Info("Secondary order")
|
|
o.processSecondaryOrder(r)
|
|
o.Type = ORDER_SECONDARY
|
|
} else {
|
|
//glog.Info("Primary order")
|
|
o.processPrimaryOrder(r)
|
|
o.Type = ORDER_PRIMARY
|
|
}
|
|
|
|
if f.OrderPdus == nil {
|
|
f.OrderPdus = make([]OrderPdu, 0, f.NumberOrders)
|
|
}
|
|
f.OrderPdus = append(f.OrderPdus, o)
|
|
}
|
|
return nil
|
|
}
|
|
func (o *OrderPdu) processAltsecOrder(r io.Reader) error {
|
|
orderType := o.ControlFlags >> 2
|
|
//glog.Info("Altsec:", orderType)
|
|
switch orderType {
|
|
case ORDER_TYPE_SWITCH_SURFACE:
|
|
case ORDER_TYPE_CREATE_OFFSCREEN_BITMAP:
|
|
case ORDER_TYPE_STREAM_BITMAP_FIRST:
|
|
case ORDER_TYPE_STREAM_BITMAP_NEXT:
|
|
case ORDER_TYPE_CREATE_NINE_GRID_BITMAP:
|
|
case ORDER_TYPE_GDIPLUS_FIRST:
|
|
case ORDER_TYPE_GDIPLUS_NEXT:
|
|
case ORDER_TYPE_GDIPLUS_END:
|
|
case ORDER_TYPE_GDIPLUS_CACHE_FIRST:
|
|
case ORDER_TYPE_GDIPLUS_CACHE_NEXT:
|
|
case ORDER_TYPE_GDIPLUS_CACHE_END:
|
|
case ORDER_TYPE_WINDOW:
|
|
case ORDER_TYPE_COMPDESK_FIRST:
|
|
case ORDER_TYPE_FRAME_MARKER:
|
|
core.ReadUInt32LE(r)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
func (o *OrderPdu) processSecondaryOrder(r io.Reader) error {
|
|
var sec Secondary
|
|
length, _ := core.ReadUint16LE(r)
|
|
flags, _ := core.ReadUint16LE(r)
|
|
orderType, _ := core.ReadUInt8(r)
|
|
|
|
glog.Info("Secondary:", SecondaryOrderType(orderType))
|
|
|
|
b, _ := core.ReadBytes(int(length)+13-6, r)
|
|
r0 := bytes.NewReader(b)
|
|
|
|
switch orderType {
|
|
case ORDER_TYPE_BITMAP_UNCOMPRESSED:
|
|
fallthrough
|
|
case ORDER_TYPE_CACHE_BITMAP_COMPRESSED:
|
|
compressed := (orderType == ORDER_TYPE_CACHE_BITMAP_COMPRESSED)
|
|
sec.updateCacheBitmapOrder(r0, compressed, flags)
|
|
case ORDER_TYPE_BITMAP_UNCOMPRESSED_V2:
|
|
fallthrough
|
|
case ORDER_TYPE_BITMAP_COMPRESSED_V2:
|
|
compressed := (orderType == ORDER_TYPE_BITMAP_COMPRESSED_V2)
|
|
sec.updateCacheBitmapV2Order(r0, compressed, flags)
|
|
case ORDER_TYPE_BITMAP_COMPRESSED_V3:
|
|
sec.updateCacheBitmapV3Order(r0, flags)
|
|
case ORDER_TYPE_CACHE_COLOR_TABLE:
|
|
sec.updateCacheColorTableOrder(r0, flags)
|
|
case ORDER_TYPE_CACHE_GLYPH:
|
|
sec.updateCacheGlyphOrder(r0, flags)
|
|
case ORDER_TYPE_CACHE_BRUSH:
|
|
sec.updateCacheBrushOrder(r0, flags)
|
|
default:
|
|
glog.Debugf("Unsupport order type 0x%x", orderType)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
func (b *Bounds) updateBounds(r io.Reader) {
|
|
present, _ := core.ReadUInt8(r)
|
|
|
|
if present&1 != 0 {
|
|
readOrderCoord(r, &b.left, false)
|
|
} else if present&16 != 0 {
|
|
readOrderCoord(r, &b.left, true)
|
|
}
|
|
|
|
if present&2 != 0 {
|
|
readOrderCoord(r, &b.top, false)
|
|
} else if present&32 != 0 {
|
|
readOrderCoord(r, &b.top, true)
|
|
}
|
|
|
|
if present&4 != 0 {
|
|
readOrderCoord(r, &b.right, false)
|
|
} else if present&64 != 0 {
|
|
readOrderCoord(r, &b.right, true)
|
|
}
|
|
if present&8 != 0 {
|
|
readOrderCoord(r, &b.bottom, false)
|
|
} else if present&128 != 0 {
|
|
readOrderCoord(r, &b.bottom, true)
|
|
}
|
|
}
|
|
|
|
type PrimaryOrder interface {
|
|
Type() int
|
|
Unpack(io.Reader, uint32, bool) error
|
|
}
|
|
|
|
var (
|
|
orderType uint8
|
|
bounds Bounds
|
|
)
|
|
|
|
func (o *OrderPdu) processPrimaryOrder(r io.Reader) error {
|
|
o.Primary = &Primary{}
|
|
if o.ControlFlags&TS_TYPE_CHANGE != 0 {
|
|
orderType, _ = core.ReadUInt8(r)
|
|
}
|
|
size := 1
|
|
switch orderType {
|
|
case ORDER_TYPE_MEM3BLT, ORDER_TYPE_TEXT2:
|
|
size = 3
|
|
|
|
case ORDER_TYPE_PATBLT, ORDER_TYPE_MEMBLT, ORDER_TYPE_LINETO, ORDER_TYPE_POLYGON_CB, ORDER_TYPE_ELLIPSE_CB:
|
|
size = 2
|
|
}
|
|
|
|
if o.ControlFlags&TS_ZERO_FIELD_BYTE_BIT0 != 0 {
|
|
size--
|
|
}
|
|
if o.ControlFlags&TS_ZERO_FIELD_BYTE_BIT1 != 0 {
|
|
if size < 2 {
|
|
size = 0
|
|
} else {
|
|
size -= 2
|
|
}
|
|
}
|
|
var present uint32
|
|
for i := 0; i < size; i++ {
|
|
bits, _ := core.ReadUInt8(r)
|
|
present |= uint32(bits) << (i * 8)
|
|
}
|
|
|
|
if o.ControlFlags&TS_BOUNDS != 0 {
|
|
if o.ControlFlags&TS_ZERO_BOUNDS_DELTAS == 0 {
|
|
bounds.updateBounds(r)
|
|
}
|
|
//glog.Infof("updateBounds")
|
|
o.Primary.Bounds = bounds
|
|
}
|
|
|
|
delta := o.ControlFlags&TS_DELTA_COORDINATES != 0
|
|
|
|
//glog.Infof("present=%d,delta=%v", present, delta)
|
|
|
|
var p PrimaryOrder
|
|
switch orderType {
|
|
case ORDER_TYPE_DSTBLT:
|
|
p = &Dstblt{}
|
|
|
|
case ORDER_TYPE_PATBLT:
|
|
p = &Patblt{}
|
|
|
|
case ORDER_TYPE_SCRBLT:
|
|
p = &Scrblt{}
|
|
|
|
//case ORDER_TYPE_DRAWNINEGRID:
|
|
|
|
//case ORDER_TYPE_MULTI_DRAWNINEGRID:
|
|
|
|
case ORDER_TYPE_LINETO:
|
|
p = &LineTo{}
|
|
|
|
case ORDER_TYPE_OPAQUERECT:
|
|
p = &OpaqueRect{}
|
|
|
|
case ORDER_TYPE_SAVEBITMAP:
|
|
p = &SaveBitmap{}
|
|
|
|
case ORDER_TYPE_MEMBLT:
|
|
p = &Memblt{}
|
|
|
|
case ORDER_TYPE_MEM3BLT:
|
|
p = &Mem3blt{}
|
|
|
|
//case ORDER_TYPE_MULTIDSTBLT:
|
|
|
|
//case ORDER_TYPE_MULTIPATBLT:
|
|
|
|
//case ORDER_TYPE_MULTISCRBLT:
|
|
|
|
//case ORDER_TYPE_MULTIOPAQUERECT:
|
|
|
|
//case ORDER_TYPE_FAST_INDEX:
|
|
|
|
case ORDER_TYPE_POLYGON_SC:
|
|
p = &PolygonSc{}
|
|
|
|
case ORDER_TYPE_POLYGON_CB:
|
|
p = &PolygonCb{}
|
|
|
|
case ORDER_TYPE_POLYLINE:
|
|
p = &Polyline{}
|
|
|
|
//case ORDER_TYPE_FAST_GLYPH:
|
|
|
|
case ORDER_TYPE_ELLIPSE_SC:
|
|
p = &EllipeSc{}
|
|
|
|
case ORDER_TYPE_ELLIPSE_CB:
|
|
p = &EllipeCb{}
|
|
|
|
case ORDER_TYPE_TEXT2:
|
|
p = &GlayphIndex{}
|
|
default:
|
|
glog.Error("Not Support order type:", orderType)
|
|
return errors.New("Not Support order type")
|
|
}
|
|
if p != nil {
|
|
if err := p.Unpack(r, present, delta); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
o.Primary.Data = p
|
|
return nil
|
|
}
|
|
func readOrderCoord(r io.Reader, coord *int32, delta bool) {
|
|
if delta {
|
|
change, _ := core.ReadUInt8(r)
|
|
*coord += int32(int8(change))
|
|
} else {
|
|
change, _ := core.ReadUint16LE(r)
|
|
*coord = int32(int16(change))
|
|
}
|
|
}
|
|
|
|
type Dstblt struct {
|
|
x int32
|
|
y int32
|
|
cx int32
|
|
cy int32
|
|
opcode uint8
|
|
}
|
|
|
|
func (d *Dstblt) Type() int {
|
|
return ORDER_TYPE_DSTBLT
|
|
}
|
|
func (d *Dstblt) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
glog.Infof("Dstblt Order")
|
|
if present&0x01 != 0 {
|
|
readOrderCoord(r, &d.x, delta)
|
|
}
|
|
if present&0x02 != 0 {
|
|
readOrderCoord(r, &d.y, delta)
|
|
}
|
|
if present&0x04 != 0 {
|
|
readOrderCoord(r, &d.cx, delta)
|
|
}
|
|
if present&0x08 != 0 {
|
|
readOrderCoord(r, &d.cy, delta)
|
|
}
|
|
if present&0x10 != 0 {
|
|
d.opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Patblt struct {
|
|
x int32
|
|
y int32
|
|
cx int32
|
|
cy int32
|
|
opcode uint8
|
|
bgcolour [4]uint8
|
|
fgcolour [4]uint8
|
|
brush Brush
|
|
}
|
|
|
|
func (d *Patblt) Type() int {
|
|
return ORDER_TYPE_PATBLT
|
|
}
|
|
func (d *Patblt) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
glog.Infof("Patblt Order")
|
|
if present&0x01 != 0 {
|
|
readOrderCoord(r, &d.x, delta)
|
|
}
|
|
if present&0x02 != 0 {
|
|
readOrderCoord(r, &d.y, delta)
|
|
}
|
|
if present&0x04 != 0 {
|
|
readOrderCoord(r, &d.cx, delta)
|
|
}
|
|
if present&0x08 != 0 {
|
|
readOrderCoord(r, &d.cy, delta)
|
|
}
|
|
if present&0x10 != 0 {
|
|
d.opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0020 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.bgcolour[0], d.bgcolour[1], d.bgcolour[2], d.bgcolour[3] = b, g, r, a
|
|
}
|
|
if present&0x0040 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.fgcolour[0], d.fgcolour[1], d.fgcolour[2], d.fgcolour[3] = b, g, r, a
|
|
}
|
|
d.brush.updateBrush(r, present>>7)
|
|
|
|
return nil
|
|
}
|
|
|
|
type Brush struct {
|
|
X uint8
|
|
Y uint8
|
|
Style uint8
|
|
Hatch uint8
|
|
Data []byte
|
|
}
|
|
|
|
func (b *Brush) updateBrush(r io.Reader, present uint32) {
|
|
if present&1 != 0 {
|
|
b.X, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&2 != 0 {
|
|
b.Y, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&4 != 0 {
|
|
b.Style, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&8 != 0 {
|
|
b.Hatch, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&16 != 0 {
|
|
data, _ := core.ReadBytes(7, r)
|
|
b.Data = make([]byte, 0, 8)
|
|
b.Data = append(b.Data, b.Hatch)
|
|
b.Data = append(b.Data, data...)
|
|
}
|
|
}
|
|
|
|
type Scrblt struct {
|
|
X int32
|
|
Y int32
|
|
Cx int32
|
|
Cy int32
|
|
Opcode uint8
|
|
Srcx int32
|
|
Srcy int32
|
|
}
|
|
|
|
func (d *Scrblt) Type() int {
|
|
return ORDER_TYPE_SCRBLT
|
|
}
|
|
|
|
var d Scrblt
|
|
|
|
func (d1 *Scrblt) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
glog.Infof("Scrblt Order")
|
|
if present&0x0001 != 0 {
|
|
readOrderCoord(r, &d.X, delta)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.Y, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
readOrderCoord(r, &d.Cx, delta)
|
|
}
|
|
if present&0x0008 != 0 {
|
|
readOrderCoord(r, &d.Cy, delta)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
d.Opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0020 != 0 {
|
|
readOrderCoord(r, &d.Srcx, delta)
|
|
}
|
|
if present&0x0040 != 0 {
|
|
readOrderCoord(r, &d.Srcy, delta)
|
|
}
|
|
*d1 = d
|
|
return nil
|
|
}
|
|
|
|
type LineTo struct {
|
|
Mixmode uint16
|
|
Startx int32
|
|
Starty int32
|
|
Endx int32
|
|
Endy int32
|
|
Bgcolour [4]uint8
|
|
Opcode uint8
|
|
Pen Pen
|
|
}
|
|
|
|
func (d *LineTo) Type() int {
|
|
return ORDER_TYPE_LINETO
|
|
}
|
|
func (d *LineTo) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
glog.Infof("LineTo Order")
|
|
if present&0x0001 != 0 {
|
|
d.Mixmode, _ = core.ReadUint16LE(r)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.Startx, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
readOrderCoord(r, &d.Starty, delta)
|
|
}
|
|
if present&0x008 != 0 {
|
|
readOrderCoord(r, &d.Endx, delta)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
readOrderCoord(r, &d.Endy, delta)
|
|
}
|
|
if present&0x0020 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.Bgcolour[0], d.Bgcolour[1], d.Bgcolour[2], d.Bgcolour[3] = b, g, r, a
|
|
}
|
|
if present&0x0040 != 0 {
|
|
d.Opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
d.Pen.updatePen(r, present>>7)
|
|
|
|
return nil
|
|
}
|
|
|
|
type Pen struct {
|
|
Style uint8
|
|
Width uint8
|
|
Colour [4]uint8
|
|
}
|
|
|
|
func (d *Pen) updatePen(r io.Reader, present uint32) {
|
|
if present&1 != 0 {
|
|
d.Style, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&2 != 0 {
|
|
d.Width, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
if present&4 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.Colour[0], d.Colour[1], d.Colour[2], d.Colour[3] = b, g, r, a
|
|
}
|
|
}
|
|
|
|
type OpaqueRect struct {
|
|
X int32
|
|
Y int32
|
|
Cx int32
|
|
Cy int32
|
|
Colour [4]uint8
|
|
}
|
|
|
|
func (d *OpaqueRect) Type() int {
|
|
return ORDER_TYPE_OPAQUERECT
|
|
}
|
|
func (d *OpaqueRect) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
glog.Infof("OpaqueRect Order")
|
|
if present&0x0001 != 0 {
|
|
readOrderCoord(r, &d.X, delta)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.Y, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
readOrderCoord(r, &d.Cx, delta)
|
|
}
|
|
if present&0x0008 != 0 {
|
|
readOrderCoord(r, &d.Cy, delta)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
i, _ := core.ReadUInt8(r)
|
|
d.Colour[0] = i
|
|
}
|
|
if present&0x0020 != 0 {
|
|
i, _ := core.ReadUInt8(r)
|
|
d.Colour[1] = i
|
|
}
|
|
if present&0x0040 != 0 {
|
|
i, _ := core.ReadUInt8(r)
|
|
d.Colour[2] = i
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type SaveBitmap struct {
|
|
Offset uint32
|
|
Left int32
|
|
Top int32
|
|
Right int32
|
|
Bottom int32
|
|
action uint8
|
|
}
|
|
|
|
func (d *SaveBitmap) Type() int {
|
|
return ORDER_TYPE_SAVEBITMAP
|
|
}
|
|
func (d *SaveBitmap) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
if present&0x0001 != 0 {
|
|
d.Offset, _ = core.ReadUInt32LE(r)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.Left, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
readOrderCoord(r, &d.Top, delta)
|
|
}
|
|
if present&0x0008 != 0 {
|
|
readOrderCoord(r, &d.Right, delta)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
readOrderCoord(r, &d.Bottom, delta)
|
|
}
|
|
if present&0x0020 != 0 {
|
|
d.action, _ = core.ReadUInt8(r)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Memblt struct {
|
|
ColourTable uint8
|
|
CacheId uint8
|
|
X int32
|
|
Y int32
|
|
Cx int32
|
|
Cy int32
|
|
Opcode uint8
|
|
Srcx int32
|
|
Srcy int32
|
|
CacheIdx uint16
|
|
}
|
|
|
|
func (d *Memblt) Type() int {
|
|
return ORDER_TYPE_MEMBLT
|
|
}
|
|
func (d *Memblt) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
if present&0x0001 != 0 {
|
|
d.CacheId, _ = core.ReadUInt8(r)
|
|
d.ColourTable, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.X, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
readOrderCoord(r, &d.Y, delta)
|
|
}
|
|
if present&0x0008 != 0 {
|
|
readOrderCoord(r, &d.Cx, delta)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
readOrderCoord(r, &d.Cy, delta)
|
|
}
|
|
if present&0x0020 != 0 {
|
|
d.Opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0040 != 0 {
|
|
readOrderCoord(r, &d.Srcx, delta)
|
|
}
|
|
if present&0x0080 != 0 {
|
|
readOrderCoord(r, &d.Srcy, delta)
|
|
}
|
|
if present&0x0100 != 0 {
|
|
d.CacheIdx, _ = core.ReadUint16LE(r)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type Mem3blt struct {
|
|
ColourTable uint8
|
|
CacheId uint8
|
|
X int32
|
|
Y int32
|
|
Cx int32
|
|
Cy int32
|
|
Opcode uint8
|
|
Srcx int32
|
|
Srcy int32
|
|
Bgcolour [4]uint8
|
|
Fgcolour [4]uint8
|
|
Brush Brush
|
|
CacheIdx uint16
|
|
}
|
|
|
|
func (d *Mem3blt) Type() int {
|
|
return ORDER_TYPE_MEM3BLT
|
|
}
|
|
func (d *Mem3blt) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
if present&0x000001 != 0 {
|
|
d.CacheId, _ = core.ReadUInt8(r)
|
|
d.ColourTable, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x000002 != 0 {
|
|
readOrderCoord(r, &d.X, delta)
|
|
}
|
|
if present&0x000004 != 0 {
|
|
readOrderCoord(r, &d.Y, delta)
|
|
}
|
|
if present&0x000008 != 0 {
|
|
readOrderCoord(r, &d.Cx, delta)
|
|
}
|
|
if present&0x000010 != 0 {
|
|
readOrderCoord(r, &d.Cy, delta)
|
|
}
|
|
if present&0x000020 != 0 {
|
|
d.Opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x000040 != 0 {
|
|
readOrderCoord(r, &d.Srcx, delta)
|
|
}
|
|
if present&0x000080 != 0 {
|
|
readOrderCoord(r, &d.Srcy, delta)
|
|
}
|
|
if present&0x000100 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.Bgcolour[0], d.Bgcolour[1], d.Bgcolour[2], d.Bgcolour[3] = b, g, r, a
|
|
}
|
|
if present&0x000200 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.Fgcolour[0], d.Fgcolour[1], d.Fgcolour[2], d.Fgcolour[3] = b, g, r, a
|
|
}
|
|
d.Brush.updateBrush(r, present>>10)
|
|
if present&0x008000 != 0 {
|
|
d.CacheIdx, _ = core.ReadUint16LE(r)
|
|
}
|
|
if present&0x010000 != 0 {
|
|
core.ReadUint16LE(r)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type PolygonSc struct {
|
|
X int32
|
|
Y int32
|
|
Opcode uint8
|
|
Fillmode uint8
|
|
Fgcolour [4]uint8
|
|
Npoints uint8
|
|
Points []Point
|
|
}
|
|
|
|
type Point struct {
|
|
X int32
|
|
Y int32
|
|
}
|
|
|
|
func (d *PolygonSc) Type() int {
|
|
return ORDER_TYPE_POLYGON_SC
|
|
}
|
|
func (d *PolygonSc) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
if present&0x0001 != 0 {
|
|
readOrderCoord(r, &d.X, delta)
|
|
}
|
|
if present&0x0002 != 0 {
|
|
readOrderCoord(r, &d.Y, delta)
|
|
}
|
|
if present&0x0004 != 0 {
|
|
d.Opcode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0008 != 0 {
|
|
d.Fillmode, _ = core.ReadUInt8(r)
|
|
}
|
|
if present&0x0010 != 0 {
|
|
b, g, r, a := updateReadColorRef(r)
|
|
d.Fgcolour[0], d.Fgcolour[1], d.Fgcolour[2], d.Fgcolour[3] = b, g, r, a
|
|
}
|
|
if present&0x0020 != 0 {
|
|
d.Npoints, _ = core.ReadUInt8(r)
|
|
d.Points = make([]Point, 0, d.Npoints+1)
|
|
}
|
|
if present&0x0040 != 0 {
|
|
size, _ := core.ReadUInt8(r)
|
|
data, _ := core.ReadBytes(int(size), r)
|
|
d.Points = append(d.Points, Point{d.X, d.Y})
|
|
var flags uint8
|
|
r = bytes.NewReader(data)
|
|
for i := 1; i <= int(d.Npoints); i++ {
|
|
var p Point
|
|
if (i-1)%4 == 0 {
|
|
flags, _ = core.ReadUInt8(r)
|
|
}
|
|
if (^flags)&0x80 != 0 {
|
|
p.X = parseDelta(r)
|
|
}
|
|
if (^flags)&0x40 != 0 {
|
|
p.Y = parseDelta(r)
|
|
}
|
|
flags <<= 2
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func parseDelta(r io.Reader) (v int32) {
|
|
b, _ := core.ReadUInt8(r)
|
|
if b&0x40 != 0 {
|
|
v = int32(b) | (^0x3F)
|
|
} else {
|
|
v = int32(b & 0x3F)
|
|
}
|
|
if b&0x80 != 0 {
|
|
b, _ := core.ReadUInt8(r)
|
|
v = (v << 8) | int32(b)
|
|
}
|
|
return
|
|
}
|
|
|
|
type PolygonCb struct {
|
|
}
|
|
|
|
func (d *PolygonCb) Type() int {
|
|
return ORDER_TYPE_POLYGON_CB
|
|
}
|
|
func (d *PolygonCb) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
return nil
|
|
}
|
|
|
|
type Polyline struct {
|
|
}
|
|
|
|
func (d *Polyline) Type() int {
|
|
return ORDER_TYPE_POLYLINE
|
|
}
|
|
func (d *Polyline) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
return nil
|
|
}
|
|
|
|
type EllipeSc struct {
|
|
}
|
|
|
|
func (d *EllipeSc) Type() int {
|
|
return ORDER_TYPE_ELLIPSE_SC
|
|
}
|
|
func (d *EllipeSc) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
return nil
|
|
}
|
|
|
|
type EllipeCb struct {
|
|
}
|
|
|
|
func (d *EllipeCb) Type() int {
|
|
return ORDER_TYPE_ELLIPSE_CB
|
|
}
|
|
func (d *EllipeCb) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
return nil
|
|
}
|
|
|
|
type GlayphIndex struct {
|
|
}
|
|
|
|
func (d *GlayphIndex) Type() int {
|
|
return ORDER_TYPE_TEXT2
|
|
}
|
|
func (d *GlayphIndex) Unpack(r io.Reader, present uint32, delta bool) error {
|
|
return nil
|
|
}
|
|
|
|
/*Secondary*/
|
|
func (s *Secondary) updateCacheBitmapOrder(r io.Reader, compressed bool, flags uint16) {
|
|
var cb CacheBitmapOrder
|
|
cb.cacheId, _ = core.ReadUInt8(r)
|
|
core.ReadUInt8(r)
|
|
cb.bitmapWidth, _ = core.ReadUInt8(r)
|
|
cb.bitmapHeight, _ = core.ReadUInt8(r)
|
|
cb.bitmapBpp, _ = core.ReadUInt8(r)
|
|
bitmapLength, _ := core.ReadUint16LE(r)
|
|
cb.cacheIndex, _ = core.ReadUint16LE(r)
|
|
var bitmapComprHdr []byte
|
|
if compressed {
|
|
if (flags & NO_BITMAP_COMPRESSION_HDR) == 0 {
|
|
bitmapComprHdr, _ = core.ReadBytes(8, r)
|
|
bitmapLength -= 8
|
|
}
|
|
}
|
|
cb.bitmapComprHdr = bitmapComprHdr
|
|
cb.bitmapDataStream, _ = core.ReadBytes(int(bitmapLength), r)
|
|
cb.bitmapLength = bitmapLength
|
|
|
|
}
|
|
|
|
type CacheBitmapOrder struct {
|
|
cacheId uint8
|
|
bitmapBpp uint8
|
|
bitmapWidth uint8
|
|
bitmapHeight uint8
|
|
bitmapLength uint16
|
|
cacheIndex uint16
|
|
bitmapComprHdr []byte
|
|
bitmapDataStream []byte
|
|
}
|
|
|
|
func getCbV2Bpp(bpp uint32) (b uint32) {
|
|
switch bpp {
|
|
case 3:
|
|
b = 8
|
|
case 4:
|
|
b = 16
|
|
case 5:
|
|
b = 24
|
|
case 6:
|
|
b = 32
|
|
default:
|
|
b = 0
|
|
}
|
|
return
|
|
}
|
|
|
|
type CacheBitmapV2Order struct {
|
|
cacheId uint32
|
|
flags uint32
|
|
key1 uint32
|
|
key2 uint32
|
|
bitmapBpp uint32
|
|
bitmapWidth uint8
|
|
bitmapHeight uint8
|
|
bitmapLength uint16
|
|
cacheIndex uint32
|
|
compressed bool
|
|
cbCompFirstRowSize uint16
|
|
cbCompMainBodySize uint16
|
|
cbScanWidth uint16
|
|
cbUncompressedSize uint16
|
|
bitmapDataStream []byte
|
|
}
|
|
|
|
func (s *Secondary) updateCacheBitmapV2Order(r io.Reader, compressed bool, flags uint16) {
|
|
var cb CacheBitmapV2Order
|
|
cb.cacheId = uint32(flags) & 0x0003
|
|
cb.flags = (uint32(flags) & 0xFF80) >> 7
|
|
bitsPerPixelId := (uint32(flags) & 0x0078) >> 3
|
|
cb.bitmapBpp = getCbV2Bpp(bitsPerPixelId)
|
|
|
|
if cb.flags&CBR2_PERSISTENT_KEY_PRESENT != 0 {
|
|
cb.key1, _ = core.ReadUInt32LE(r)
|
|
cb.key2, _ = core.ReadUInt32LE(r)
|
|
}
|
|
|
|
if cb.flags&CBR2_HEIGHT_SAME_AS_WIDTH != 0 {
|
|
cb.bitmapWidth, _ = core.ReadUInt8(r)
|
|
cb.bitmapHeight = cb.bitmapWidth
|
|
} else {
|
|
cb.bitmapWidth, _ = core.ReadUInt8(r)
|
|
cb.bitmapHeight, _ = core.ReadUInt8(r)
|
|
}
|
|
|
|
bitmapLength, _ := core.ReadUint16LE(r)
|
|
cacheIndex, _ := core.ReadUInt8(r)
|
|
|
|
if cb.flags&CBR2_DO_NOT_CACHE != 0 {
|
|
cb.cacheIndex = 0x7FFF
|
|
} else {
|
|
cb.cacheIndex = uint32(cacheIndex)
|
|
}
|
|
|
|
if compressed {
|
|
if cb.flags&CBR2_NO_BITMAP_COMPRESSION_HDR == 0 {
|
|
cb.cbCompFirstRowSize, _ = core.ReadUint16LE(r)
|
|
cb.cbCompMainBodySize, _ = core.ReadUint16LE(r)
|
|
cb.cbScanWidth, _ = core.ReadUint16LE(r)
|
|
cb.cbUncompressedSize, _ = core.ReadUint16LE(r)
|
|
bitmapLength = cb.cbCompMainBodySize
|
|
}
|
|
}
|
|
|
|
cb.bitmapDataStream, _ = core.ReadBytes(int(bitmapLength), r)
|
|
cb.bitmapLength = bitmapLength
|
|
cb.compressed = compressed
|
|
|
|
}
|
|
|
|
type CacheBitmapV3Order struct {
|
|
cacheId uint32
|
|
bpp uint32
|
|
flags uint32
|
|
cacheIndex uint16
|
|
key1 uint32
|
|
key2 uint32
|
|
bitmapData BitmapDataEx
|
|
}
|
|
type BitmapDataEx struct {
|
|
bpp uint8
|
|
codecID uint8
|
|
width uint16
|
|
height uint16
|
|
length uint32
|
|
data []byte
|
|
}
|
|
|
|
func (s *Secondary) updateCacheBitmapV3Order(r io.Reader, flags uint16) {
|
|
var cb CacheBitmapV3Order
|
|
|
|
cb.cacheId = uint32(flags) & 0x00000003
|
|
cb.flags = (uint32(flags) & 0x0000FF80) >> 7
|
|
bitsPerPixelId := (uint32(flags) & 0x00000078) >> 3
|
|
cb.bpp = getCbV2Bpp(bitsPerPixelId)
|
|
|
|
cacheIndex, _ := core.ReadUint16LE(r)
|
|
cb.cacheIndex = cacheIndex
|
|
cb.key1, _ = core.ReadUInt32LE(r)
|
|
cb.key2, _ = core.ReadUInt32LE(r)
|
|
|
|
bitmapData := &cb.bitmapData
|
|
bitmapData.bpp, _ = core.ReadUInt8(r)
|
|
core.ReadUInt8(r)
|
|
core.ReadUInt8(r)
|
|
bitmapData.codecID, _ = core.ReadUInt8(r)
|
|
bitmapData.width, _ = core.ReadUint16LE(r)
|
|
bitmapData.height, _ = core.ReadUint16LE(r)
|
|
new_len, _ := core.ReadUInt32LE(r)
|
|
|
|
bitmapData.data, _ = core.ReadBytes(int(new_len), r)
|
|
bitmapData.length = new_len
|
|
|
|
}
|
|
|
|
type CacheColorTableOrder struct {
|
|
cacheIndex uint8
|
|
numberColors uint16
|
|
colorTable [256 * 4]uint8
|
|
}
|
|
|
|
func (s *Secondary) updateCacheColorTableOrder(r io.Reader, flags uint16) {
|
|
var cb CacheColorTableOrder
|
|
cb.cacheIndex, _ = core.ReadUInt8(r)
|
|
cb.numberColors, _ = core.ReadUint16LE(r)
|
|
|
|
if cb.numberColors != 256 {
|
|
/* This field MUST be set to 256 */
|
|
return
|
|
}
|
|
|
|
for i := 0; i < int(cb.numberColors)*4; i++ {
|
|
cb.colorTable[i], cb.colorTable[i+1], cb.colorTable[i+2], cb.colorTable[i+3] = updateReadColorRef(r)
|
|
}
|
|
}
|
|
func updateReadColorRef(r io.Reader) (uint8, uint8, uint8, uint8) {
|
|
blue, _ := core.ReadUInt8(r)
|
|
green, _ := core.ReadUInt8(r)
|
|
red, _ := core.ReadUInt8(r)
|
|
core.ReadUInt8(r)
|
|
|
|
return blue, green, red, 255
|
|
}
|
|
|
|
type CacheGlyphOrder struct {
|
|
cacheId uint8
|
|
nglyphs uint8
|
|
glyphs []CacheGlyph
|
|
}
|
|
type CacheGlyph struct {
|
|
character uint16
|
|
offset uint16
|
|
baseline uint16
|
|
width uint16
|
|
height uint16
|
|
datasize int
|
|
data []uint8
|
|
}
|
|
|
|
func (s *Secondary) updateCacheGlyphOrder(r io.Reader, flags uint16) {
|
|
var cb CacheGlyphOrder
|
|
|
|
cb.cacheId, _ = core.ReadUInt8(r)
|
|
cb.nglyphs, _ = core.ReadUInt8(r)
|
|
cb.glyphs = make([]CacheGlyph, 0, cb.nglyphs)
|
|
|
|
for i := 0; i < int(cb.nglyphs); i++ {
|
|
var c CacheGlyph
|
|
c.character, _ = core.ReadUint16LE(r)
|
|
c.offset, _ = core.ReadUint16LE(r)
|
|
c.baseline, _ = core.ReadUint16LE(r)
|
|
c.width, _ = core.ReadUint16LE(r)
|
|
c.height, _ = core.ReadUint16LE(r)
|
|
|
|
c.datasize = int(c.height*((c.width+7)/8)+3) & ^3
|
|
c.data, _ = core.ReadBytes(c.datasize, r)
|
|
|
|
cb.glyphs = append(cb.glyphs, c)
|
|
}
|
|
}
|
|
|
|
type CacheBrushOrder struct {
|
|
index uint8
|
|
bpp uint8
|
|
cx uint8
|
|
cy uint8
|
|
style uint8
|
|
length uint8
|
|
data []uint8
|
|
}
|
|
|
|
func (s *Secondary) updateCacheBrushOrder(r io.Reader, flags uint16) {
|
|
var cb CacheBrushOrder
|
|
cb.index, _ = core.ReadUInt8(r)
|
|
cb.bpp, _ = core.ReadUInt8(r)
|
|
cb.cx, _ = core.ReadUInt8(r)
|
|
cb.cy, _ = core.ReadUInt8(r)
|
|
cb.style, _ = core.ReadUInt8(r)
|
|
cb.length, _ = core.ReadUInt8(r)
|
|
if cb.cx == 8 && cb.cy == 8 {
|
|
if cb.bpp == 1 {
|
|
for i := 7; i >= 0; i-- {
|
|
cb.data[i], _ = core.ReadUInt8(r)
|
|
}
|
|
} else {
|
|
bpp := int(cb.bpp) - 2
|
|
if int(cb.length) == 16+4*bpp {
|
|
/* compressed brush */
|
|
data, _ := core.ReadBytes(int(cb.length), r)
|
|
cb.data = update_decompress_brush(data, bpp)
|
|
} else {
|
|
/* uncompressed brush */
|
|
scanline := 8 * 8 * bpp
|
|
cb.data, _ = core.ReadBytes(scanline, r)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
func update_decompress_brush(in []uint8, bpp int) []uint8 {
|
|
var pal_index, in_index, shift int
|
|
|
|
pal := in[16:]
|
|
out := make([]uint8, 8*8*bpp)
|
|
/* read it bottom up */
|
|
for y := 7; y >= 0; y-- {
|
|
/* 2 bytes per row */
|
|
x := 0
|
|
for do2 := 0; do2 < 2; do2++ {
|
|
/* 4 pixels per byte */
|
|
shift = 6
|
|
for shift >= 0 {
|
|
pal_index = int((in[in_index] >> shift) & 3)
|
|
/* size of palette entries depends on bpp */
|
|
for i := 0; i < bpp; i++ {
|
|
out[(y*8+x)*bpp+i] = pal[pal_index*bpp+i]
|
|
}
|
|
x++
|
|
shift -= 2
|
|
}
|
|
in_index++
|
|
}
|
|
}
|
|
|
|
return out
|
|
}
|
|
|
|
/*Primary*/
|
|
type Bounds struct {
|
|
left int32
|
|
top int32
|
|
right int32
|
|
bottom int32
|
|
}
|
|
type OrderInfo struct {
|
|
controlFlags uint32
|
|
orderType uint32
|
|
fieldFlags uint32
|
|
boundsFlags uint32
|
|
bounds Bounds
|
|
deltaCoordinates bool
|
|
}
|