mirror of https://github.com/tp4a/teleport
.temp. new rdp-player.
parent
f5b00ca02a
commit
0b020810b2
|
@ -0,0 +1,15 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
//#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||||
|
// QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
MainWindow w;
|
||||||
|
w.show();
|
||||||
|
|
||||||
|
return a.exec();
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "ui_mainwindow.h"
|
||||||
|
#include "rle.h"
|
||||||
|
|
||||||
|
#include <QMatrix>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
bool rdpimg2QImage(QImage& out, int w, int h, int bitsPerPixel, bool isCompressed, uint8_t* dat, uint32_t len) {
|
||||||
|
switch(bitsPerPixel) {
|
||||||
|
case 15:
|
||||||
|
if(isCompressed) {
|
||||||
|
uint8_t* _dat = (uint8_t*)calloc(1, w*h*2);
|
||||||
|
if(!bitmap_decompress1(_dat, w, h, dat, len)) {
|
||||||
|
free(_dat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out = QImage(_dat, w, h, QImage::Format_RGB555);
|
||||||
|
free(_dat);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out = QImage(dat, w, h, QImage::Format_RGB555).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
if(isCompressed) {
|
||||||
|
uint8_t* _dat = (uint8_t*)calloc(1, w*h*2);
|
||||||
|
if(!bitmap_decompress2(_dat, w, h, dat, len)) {
|
||||||
|
free(_dat);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out = QImage(_dat, w, h, QImage::Format_RGB16);
|
||||||
|
free(_dat);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
out = QImage(dat, w, h, QImage::Format_RGB16).transformed(QMatrix(1.0, 0.0, 0.0, -1.0, 0.0, 0.0)) ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
qDebug() << "--------NOT support 24";
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
qDebug() << "--------NOT support 32";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MainWindow::MainWindow(QWidget *parent) :
|
||||||
|
QMainWindow(parent),
|
||||||
|
ui(new Ui::MainWindow)
|
||||||
|
{
|
||||||
|
m_shown = false;
|
||||||
|
m_show_bg = true;
|
||||||
|
m_bg = QImage(":/tp-player/res/bg");
|
||||||
|
m_pt_normal = QImage(":/tp-player/res/cursor.png");
|
||||||
|
|
||||||
|
qDebug() << m_pt_normal.width() << "x" << m_pt_normal.height();
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
//qRegisterMetaType<update_data*>("update_data");
|
||||||
|
|
||||||
|
// frame-less window.
|
||||||
|
//#ifdef __APPLE__
|
||||||
|
// setWindowFlags(Qt::FramelessWindowHint | Qt::MSWindowsFixedSizeDialogHint | Qt::Window);
|
||||||
|
// OSXCode::fixWin(winId());
|
||||||
|
//#else
|
||||||
|
// setWindowFlags(Qt::FramelessWindowHint | Qt::MSWindowsFixedSizeDialogHint | windowFlags());
|
||||||
|
//#endif //__APPLE__
|
||||||
|
|
||||||
|
setWindowFlags(windowFlags()&~Qt::WindowMaximizeButtonHint); // 禁止最大化按钮
|
||||||
|
//setFixedSize(this->width(),this->height()); // 禁止拖动窗口大小
|
||||||
|
|
||||||
|
resize(m_bg.width(), m_bg.height());
|
||||||
|
|
||||||
|
connect(&m_thr_play, SIGNAL(signal_update_data(update_data*)), this, SLOT(on_update_data(update_data*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
MainWindow::~MainWindow()
|
||||||
|
{
|
||||||
|
m_thr_play.stop();
|
||||||
|
m_thr_play.wait();
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::paintEvent(QPaintEvent *)
|
||||||
|
{
|
||||||
|
QPainter painter(this);
|
||||||
|
|
||||||
|
if(m_show_bg) {
|
||||||
|
//qDebug() << "draw bg.";
|
||||||
|
painter.setBrush(Qt::black);
|
||||||
|
painter.drawRect(this->rect());
|
||||||
|
|
||||||
|
int x = (rect().width() - m_bg.width()) / 2;
|
||||||
|
int y = (rect().height() - m_bg.height()) / 2;
|
||||||
|
painter.drawImage(x, y, m_bg);
|
||||||
|
//painter.drawPixmap(rect(), m_bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
painter.drawImage(m_img_update_x, m_img_update_y, m_img_update, 0, 0, m_img_update_w, m_img_update_h, Qt::AutoColor);
|
||||||
|
//qDebug() << "draw pt (" << m_pt.x << "," << m_pt.y << ")";
|
||||||
|
painter.drawImage(m_pt.x, m_pt.y, m_pt_normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(!m_shown) {
|
||||||
|
m_shown = true;
|
||||||
|
m_thr_play.start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_update_data(update_data* dat) {
|
||||||
|
if(!dat)
|
||||||
|
return;
|
||||||
|
// qDebug() << "slot-event: " << dat->data_type();
|
||||||
|
|
||||||
|
if(dat->data_type() == TYPE_DATA) {
|
||||||
|
m_show_bg = false;
|
||||||
|
|
||||||
|
if(dat->data_len() <= sizeof(TS_RECORD_PKG)) {
|
||||||
|
qDebug() << "invalid record package(1).";
|
||||||
|
delete dat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TS_RECORD_PKG* pkg = (TS_RECORD_PKG*)dat->data_buf();
|
||||||
|
|
||||||
|
if(pkg->type == TS_RECORD_TYPE_RDP_POINTER) {
|
||||||
|
if(dat->data_len() != sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_POINTER)) {
|
||||||
|
qDebug() << "invalid record package(2).";
|
||||||
|
delete dat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&m_pt, dat->data_buf() + sizeof(TS_RECORD_PKG), sizeof(TS_RECORD_RDP_POINTER));
|
||||||
|
update();
|
||||||
|
//update(m_pt.x - 8, m_pt.y - 8, 32, 32);
|
||||||
|
}
|
||||||
|
else if(pkg->type == TS_RECORD_TYPE_RDP_IMAGE) {
|
||||||
|
if(dat->data_len() <= sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_IMAGE_INFO)) {
|
||||||
|
qDebug() << "invalid record package(3).";
|
||||||
|
delete dat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TS_RECORD_RDP_IMAGE_INFO* info = (TS_RECORD_RDP_IMAGE_INFO*)(dat->data_buf() + sizeof(TS_RECORD_PKG));
|
||||||
|
uint8_t* img_dat = dat->data_buf() + sizeof(TS_RECORD_PKG) + sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||||
|
uint32_t img_len = dat->data_len() - sizeof(TS_RECORD_PKG) - sizeof(TS_RECORD_RDP_IMAGE_INFO);
|
||||||
|
|
||||||
|
rdpimg2QImage(m_img_update, info->width, info->height, info->bitsPerPixel, (info->format == TS_RDP_IMG_BMP) ? true : false, img_dat, img_len);
|
||||||
|
m_img_update_x = info->destLeft;
|
||||||
|
m_img_update_y = info->destTop;
|
||||||
|
m_img_update_w = info->destRight - info->destLeft + 1;
|
||||||
|
m_img_update_h = info->destBottom - info->destTop + 1;
|
||||||
|
|
||||||
|
qDebug() << "img " << ((info->format == TS_RDP_IMG_BMP) ? "+" : " ") << " (" << m_img_update_x << "," << m_img_update_y << "), [" << m_img_update.width() << "x" << m_img_update.height() << "]";
|
||||||
|
|
||||||
|
|
||||||
|
update(m_img_update_x, m_img_update_y, m_img_update_w, m_img_update_h);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete dat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(dat->data_type() == TYPE_HEADER_INFO) {
|
||||||
|
if(dat->data_len() != sizeof(TS_RECORD_HEADER)) {
|
||||||
|
qDebug() << "invalid record header.";
|
||||||
|
delete dat;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(&m_rec_hdr, dat->data_buf(), sizeof(TS_RECORD_HEADER));
|
||||||
|
delete dat;
|
||||||
|
|
||||||
|
qDebug() << "resize (" << m_rec_hdr.basic.width << "," << m_rec_hdr.basic.height << ")";
|
||||||
|
if(m_rec_hdr.basic.width > 0 && m_rec_hdr.basic.height > 0) {
|
||||||
|
resize(m_rec_hdr.basic.width, m_rec_hdr.basic.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString title;
|
||||||
|
if (m_rec_hdr.basic.conn_port == 3389)
|
||||||
|
title.sprintf("[%s] %s@%s [Teleport-RDP录像回放]", m_rec_hdr.basic.acc_username, m_rec_hdr.basic.user_username, m_rec_hdr.basic.conn_ip);
|
||||||
|
else
|
||||||
|
title.sprintf("[%s] %s@%s:%d [Teleport-RDP录像回放]", m_rec_hdr.basic.acc_username, m_rec_hdr.basic.user_username, m_rec_hdr.basic.conn_ip, m_rec_hdr.basic.conn_port);
|
||||||
|
|
||||||
|
setWindowTitle(title);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
delete dat;
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef MAINWINDOW_H
|
||||||
|
#define MAINWINDOW_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include "thr_play.h"
|
||||||
|
#include "update_data.h"
|
||||||
|
#include "record_format.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class MainWindow;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MainWindow : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
|
~MainWindow();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void paintEvent(QPaintEvent *);
|
||||||
|
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_update_data(update_data*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::MainWindow *ui;
|
||||||
|
QImage m_bg;
|
||||||
|
QImage m_pt_normal;
|
||||||
|
QImage m_img_update;
|
||||||
|
//QPixmap m_bg1;
|
||||||
|
bool m_shown;
|
||||||
|
|
||||||
|
ThreadPlay m_thr_play;
|
||||||
|
|
||||||
|
bool m_show_bg;
|
||||||
|
TS_RECORD_HEADER m_rec_hdr;
|
||||||
|
TS_RECORD_RDP_POINTER m_pt;
|
||||||
|
|
||||||
|
int m_img_update_x;
|
||||||
|
int m_img_update_y;
|
||||||
|
int m_img_update_w;
|
||||||
|
int m_img_update_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>360</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Teleport Replayer</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralWidget"/>
|
||||||
|
<widget class="QMenuBar" name="menuBar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>500</width>
|
||||||
|
<height>17</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusBar">
|
||||||
|
<property name="sizeGripEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef RECORD_FORMAT_H
|
||||||
|
#define RECORD_FORMAT_H
|
||||||
|
|
||||||
|
#include <Qt>
|
||||||
|
|
||||||
|
|
||||||
|
#define TYPE_HEADER_INFO 0
|
||||||
|
#define TYPE_DATA 1
|
||||||
|
|
||||||
|
|
||||||
|
#define TS_RECORD_TYPE_RDP_POINTER 0x12 // 鼠标坐标位置改变,用于绘制虚拟鼠标
|
||||||
|
#define TS_RECORD_TYPE_RDP_IMAGE 0x13 // 服务端返回的图像,用于展示
|
||||||
|
|
||||||
|
#define TS_RDP_BTN_FREE 0
|
||||||
|
#define TS_RDP_BTN_PRESSED 1
|
||||||
|
#define TS_RDP_IMG_RAW 0 // 未压缩,原始数据(根据bitsPerPixel,多个字节对应一个点的颜色)
|
||||||
|
#define TS_RDP_IMG_BMP 1 // 压缩的BMP数据
|
||||||
|
|
||||||
|
#pragma pack(push,1)
|
||||||
|
|
||||||
|
// 录像文件头(随着录像数据写入,会改变的部分)
|
||||||
|
typedef struct TS_RECORD_HEADER_INFO {
|
||||||
|
uint32_t magic; // "TPPR" 标志 TelePort Protocol Record
|
||||||
|
uint16_t ver; // 录像文件版本,目前为3
|
||||||
|
uint32_t packages; // 总包数
|
||||||
|
uint32_t time_ms; // 总耗时(毫秒)
|
||||||
|
//uint32_t file_size; // 数据文件大小
|
||||||
|
}TS_RECORD_HEADER_INFO;
|
||||||
|
#define ts_record_header_info_size sizeof(TS_RECORD_HEADER_INFO)
|
||||||
|
|
||||||
|
// 录像文件头(固定不变部分)
|
||||||
|
typedef struct TS_RECORD_HEADER_BASIC {
|
||||||
|
uint16_t protocol_type; // 协议:1=RDP, 2=SSH, 3=Telnet
|
||||||
|
uint16_t protocol_sub_type; // 子协议:100=RDP-DESKTOP, 200=SSH-SHELL, 201=SSH-SFTP, 300=Telnet
|
||||||
|
uint64_t timestamp; // 本次录像的起始时间(UTC时间戳)
|
||||||
|
uint16_t width; // 初始屏幕尺寸:宽
|
||||||
|
uint16_t height; // 初始屏幕尺寸:高
|
||||||
|
char user_username[64]; // teleport账号
|
||||||
|
char acc_username[64]; // 远程主机用户名
|
||||||
|
|
||||||
|
char host_ip[40]; // 远程主机IP
|
||||||
|
char conn_ip[40]; // 远程主机IP
|
||||||
|
uint16_t conn_port; // 远程主机端口
|
||||||
|
|
||||||
|
char client_ip[40]; // 客户端IP
|
||||||
|
|
||||||
|
// // RDP专有
|
||||||
|
// uint8_t rdp_security; // 0 = RDP, 1 = TLS
|
||||||
|
|
||||||
|
// uint8_t _reserve[512 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 40 - 2 - 40 - 1 - ts_record_header_info_size];
|
||||||
|
uint8_t _reserve[512 - 2 - 2 - 8 - 2 - 2 - 64 - 64 - 40 - 40 - 2 - 40 - ts_record_header_info_size];
|
||||||
|
}TS_RECORD_HEADER_BASIC;
|
||||||
|
#define ts_record_header_basic_size sizeof(TS_RECORD_HEADER_BASIC)
|
||||||
|
|
||||||
|
typedef struct TS_RECORD_HEADER {
|
||||||
|
TS_RECORD_HEADER_INFO info;
|
||||||
|
TS_RECORD_HEADER_BASIC basic;
|
||||||
|
}TS_RECORD_HEADER;
|
||||||
|
|
||||||
|
// header部分(header-info + header-basic) = 512B
|
||||||
|
#define ts_record_header_size sizeof(TS_RECORD_HEADER)
|
||||||
|
|
||||||
|
// 一个数据包的头
|
||||||
|
typedef struct TS_RECORD_PKG {
|
||||||
|
uint8_t type; // 包的数据类型
|
||||||
|
uint32_t size; // 这个包的总大小(不含包头)
|
||||||
|
uint32_t time_ms; // 这个包距起始时间的时间差(毫秒,意味着一个连接不能持续超过49天)
|
||||||
|
uint8_t _reserve[3]; // 保留
|
||||||
|
}TS_RECORD_PKG;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct TS_RECORD_RDP_POINTER {
|
||||||
|
uint16_t x;
|
||||||
|
uint16_t y;
|
||||||
|
uint8_t button;
|
||||||
|
uint8_t pressed;
|
||||||
|
}TS_RECORD_RDP_POINTER;
|
||||||
|
|
||||||
|
// RDP图像更新
|
||||||
|
typedef struct TS_RECORD_RDP_IMAGE_INFO {
|
||||||
|
uint16_t destLeft;
|
||||||
|
uint16_t destTop;
|
||||||
|
uint16_t destRight;
|
||||||
|
uint16_t destBottom;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
uint16_t bitsPerPixel;
|
||||||
|
uint8_t format;
|
||||||
|
uint8_t _reserved;
|
||||||
|
}TS_RECORD_RDP_IMAGE_INFO;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RECORD_FORMAT_H
|
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
|
@ -0,0 +1,974 @@
|
||||||
|
/* -*- c-basic-offset: 8 -*-
|
||||||
|
rdesktop: A Remote Desktop Protocol client.
|
||||||
|
Bitmap decompression routines
|
||||||
|
Copyright (C) Matthew Chapman <matthewc.unsw.edu.au> 1999-2008
|
||||||
|
|
||||||
|
This program 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 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program 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 program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* three seperate function for speed when decompressing the bitmaps
|
||||||
|
when modifing one function make the change in the others
|
||||||
|
jay.sorg@gmail.com */
|
||||||
|
|
||||||
|
/* indent is confused by this file */
|
||||||
|
/* *INDENT-OFF* */
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "rle.h"
|
||||||
|
|
||||||
|
/* Specific rename for RDPY integration */
|
||||||
|
#define unimpl(str, code)
|
||||||
|
|
||||||
|
//#define RD_BOOL int
|
||||||
|
//#define False 0
|
||||||
|
//#define True 1
|
||||||
|
/* end specific rename */
|
||||||
|
|
||||||
|
#define CVAL(p) (*(p++))
|
||||||
|
//#ifdef NEED_ALIGN
|
||||||
|
//#ifdef L_ENDIAN
|
||||||
|
#define CVAL2(p, v) { v = (*(p++)); v |= (*(p++)) << 8; }
|
||||||
|
//#else
|
||||||
|
//#define CVAL2(p, v) { v = (*(p++)) << 8; v |= (*(p++)); }
|
||||||
|
//#endif /* L_ENDIAN */
|
||||||
|
//#else
|
||||||
|
//#define CVAL2(p, v) { v = (*((uint16*)p)); p += 2; }
|
||||||
|
//#endif /* NEED_ALIGN */
|
||||||
|
|
||||||
|
#define UNROLL8(exp) { exp exp exp exp exp exp exp exp }
|
||||||
|
|
||||||
|
#define REPEAT(statement) \
|
||||||
|
{ \
|
||||||
|
while((count & ~0x7) && ((x+8) < width)) \
|
||||||
|
UNROLL8( statement; count--; x++; ); \
|
||||||
|
\
|
||||||
|
while((count > 0) && (x < width)) \
|
||||||
|
{ \
|
||||||
|
statement; \
|
||||||
|
count--; \
|
||||||
|
x++; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define MASK_UPDATE() \
|
||||||
|
{ \
|
||||||
|
mixmask <<= 1; \
|
||||||
|
if (mixmask == 0) \
|
||||||
|
{ \
|
||||||
|
mask = fom_mask ? fom_mask : CVAL(input); \
|
||||||
|
mixmask = 1; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 1 byte bitmap decompress */
|
||||||
|
RD_BOOL
|
||||||
|
bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size)
|
||||||
|
{
|
||||||
|
uint8 *end = input + size;
|
||||||
|
uint8 *prevline = NULL, *line = NULL;
|
||||||
|
int opcode, count, offset, isfillormix, x = width;
|
||||||
|
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||||
|
uint8 code;
|
||||||
|
uint8 colour1 = 0, colour2 = 0;
|
||||||
|
uint8 mixmask, mask = 0;
|
||||||
|
uint8 mix = 0xff;
|
||||||
|
int fom_mask = 0;
|
||||||
|
|
||||||
|
while (input < end)
|
||||||
|
{
|
||||||
|
fom_mask = 0;
|
||||||
|
code = CVAL(input);
|
||||||
|
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 = CVAL(input);
|
||||||
|
count |= CVAL(input) << 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 = CVAL(input) + 1;
|
||||||
|
else
|
||||||
|
count = CVAL(input) + offset;
|
||||||
|
}
|
||||||
|
else if (isfillormix)
|
||||||
|
{
|
||||||
|
count <<= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Read preliminary data */
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||||
|
insertmix = True;
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
colour1 = CVAL(input);
|
||||||
|
case 3: /* Colour */
|
||||||
|
colour2 = CVAL(input);
|
||||||
|
break;
|
||||||
|
case 6: /* SetMix/Mix */
|
||||||
|
case 7: /* SetMix/FillOrMix */
|
||||||
|
mix = CVAL(input);
|
||||||
|
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)
|
||||||
|
return False;
|
||||||
|
x = 0;
|
||||||
|
height--;
|
||||||
|
prevline = line;
|
||||||
|
line = output + height * width;
|
||||||
|
}
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if (insertmix)
|
||||||
|
{
|
||||||
|
if (prevline == NULL)
|
||||||
|
line[x] = mix;
|
||||||
|
else
|
||||||
|
line[x] = prevline[x] ^ mix;
|
||||||
|
insertmix = False;
|
||||||
|
count--;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = 0)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = prevline[x])
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: /* Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = mix)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = prevline[x] ^ mix)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /* Fill or Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
line[x] = mix;
|
||||||
|
else
|
||||||
|
line[x] = 0;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
line[x] = prevline[x] ^ mix;
|
||||||
|
else
|
||||||
|
line[x] = prevline[x];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: /* Colour */
|
||||||
|
REPEAT(line[x] = colour2)
|
||||||
|
break;
|
||||||
|
case 4: /* Copy */
|
||||||
|
REPEAT(line[x] = CVAL(input))
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
if (bicolour)
|
||||||
|
{
|
||||||
|
line[x] = colour2;
|
||||||
|
bicolour = False;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x] = colour1;
|
||||||
|
bicolour = True; count++;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 0xd: /* White */
|
||||||
|
REPEAT(line[x] = 0xff)
|
||||||
|
break;
|
||||||
|
case 0xe: /* Black */
|
||||||
|
REPEAT(line[x] = 0)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 2 byte bitmap decompress */
|
||||||
|
RD_BOOL
|
||||||
|
bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size)
|
||||||
|
{
|
||||||
|
uint8 *end = input + size;
|
||||||
|
uint16 *prevline = NULL, *line = NULL;
|
||||||
|
int opcode, count, offset, isfillormix, x = width;
|
||||||
|
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||||
|
uint8 code;
|
||||||
|
uint16 colour1 = 0, colour2 = 0;
|
||||||
|
uint8 mixmask, mask = 0;
|
||||||
|
uint16 mix = 0xffff;
|
||||||
|
int fom_mask = 0;
|
||||||
|
|
||||||
|
while (input < end)
|
||||||
|
{
|
||||||
|
fom_mask = 0;
|
||||||
|
code = CVAL(input);
|
||||||
|
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 = CVAL(input);
|
||||||
|
count |= CVAL(input) << 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 = CVAL(input) + 1;
|
||||||
|
else
|
||||||
|
count = CVAL(input) + offset;
|
||||||
|
}
|
||||||
|
else if (isfillormix)
|
||||||
|
{
|
||||||
|
count <<= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Read preliminary data */
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||||
|
insertmix = True;
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
CVAL2(input, colour1);
|
||||||
|
case 3: /* Colour */
|
||||||
|
CVAL2(input, colour2);
|
||||||
|
break;
|
||||||
|
case 6: /* SetMix/Mix */
|
||||||
|
case 7: /* SetMix/FillOrMix */
|
||||||
|
CVAL2(input, mix);
|
||||||
|
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)
|
||||||
|
return False;
|
||||||
|
x = 0;
|
||||||
|
height--;
|
||||||
|
prevline = line;
|
||||||
|
line = ((uint16 *) output) + height * width;
|
||||||
|
}
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if (insertmix)
|
||||||
|
{
|
||||||
|
if (prevline == NULL)
|
||||||
|
line[x] = mix;
|
||||||
|
else
|
||||||
|
line[x] = prevline[x] ^ mix;
|
||||||
|
insertmix = False;
|
||||||
|
count--;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = 0)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = prevline[x])
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: /* Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = mix)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT(line[x] = prevline[x] ^ mix)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /* Fill or Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
line[x] = mix;
|
||||||
|
else
|
||||||
|
line[x] = 0;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
line[x] = prevline[x] ^ mix;
|
||||||
|
else
|
||||||
|
line[x] = prevline[x];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: /* Colour */
|
||||||
|
REPEAT(line[x] = colour2)
|
||||||
|
break;
|
||||||
|
case 4: /* Copy */
|
||||||
|
REPEAT(CVAL2(input, line[x]))
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
if (bicolour)
|
||||||
|
{
|
||||||
|
line[x] = colour2;
|
||||||
|
bicolour = False;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x] = colour1;
|
||||||
|
bicolour = True;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 0xd: /* White */
|
||||||
|
REPEAT(line[x] = 0xffff)
|
||||||
|
break;
|
||||||
|
case 0xe: /* Black */
|
||||||
|
REPEAT(line[x] = 0)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3 byte bitmap decompress */
|
||||||
|
RD_BOOL
|
||||||
|
bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size)
|
||||||
|
{
|
||||||
|
uint8 *end = input + size;
|
||||||
|
uint8 *prevline = NULL, *line = NULL;
|
||||||
|
int opcode, count, offset, isfillormix, x = width;
|
||||||
|
int lastopcode = -1, insertmix = False, bicolour = False;
|
||||||
|
uint8 code;
|
||||||
|
uint8 colour1[3] = {0, 0, 0}, colour2[3] = {0, 0, 0};
|
||||||
|
uint8 mixmask, mask = 0;
|
||||||
|
uint8 mix[3] = {0xff, 0xff, 0xff};
|
||||||
|
int fom_mask = 0;
|
||||||
|
|
||||||
|
while (input < end)
|
||||||
|
{
|
||||||
|
fom_mask = 0;
|
||||||
|
code = CVAL(input);
|
||||||
|
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 = CVAL(input);
|
||||||
|
count |= CVAL(input) << 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 = CVAL(input) + 1;
|
||||||
|
else
|
||||||
|
count = CVAL(input) + offset;
|
||||||
|
}
|
||||||
|
else if (isfillormix)
|
||||||
|
{
|
||||||
|
count <<= 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Read preliminary data */
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if ((lastopcode == opcode) && !((x == width) && (prevline == NULL)))
|
||||||
|
insertmix = True;
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
colour1[0] = CVAL(input);
|
||||||
|
colour1[1] = CVAL(input);
|
||||||
|
colour1[2] = CVAL(input);
|
||||||
|
case 3: /* Colour */
|
||||||
|
colour2[0] = CVAL(input);
|
||||||
|
colour2[1] = CVAL(input);
|
||||||
|
colour2[2] = CVAL(input);
|
||||||
|
break;
|
||||||
|
case 6: /* SetMix/Mix */
|
||||||
|
case 7: /* SetMix/FillOrMix */
|
||||||
|
mix[0] = CVAL(input);
|
||||||
|
mix[1] = CVAL(input);
|
||||||
|
mix[2] = CVAL(input);
|
||||||
|
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)
|
||||||
|
return False;
|
||||||
|
x = 0;
|
||||||
|
height--;
|
||||||
|
prevline = line;
|
||||||
|
line = output + height * (width * 3);
|
||||||
|
}
|
||||||
|
switch (opcode)
|
||||||
|
{
|
||||||
|
case 0: /* Fill */
|
||||||
|
if (insertmix)
|
||||||
|
{
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
line[x * 3] = mix[0];
|
||||||
|
line[x * 3 + 1] = mix[1];
|
||||||
|
line[x * 3 + 2] = mix[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x * 3] =
|
||||||
|
prevline[x * 3] ^ mix[0];
|
||||||
|
line[x * 3 + 1] =
|
||||||
|
prevline[x * 3 + 1] ^ mix[1];
|
||||||
|
line[x * 3 + 2] =
|
||||||
|
prevline[x * 3 + 2] ^ mix[2];
|
||||||
|
}
|
||||||
|
insertmix = False;
|
||||||
|
count--;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = 0;
|
||||||
|
line[x * 3 + 1] = 0;
|
||||||
|
line[x * 3 + 2] = 0;
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = prevline[x * 3];
|
||||||
|
line[x * 3 + 1] = prevline[x * 3 + 1];
|
||||||
|
line[x * 3 + 2] = prevline[x * 3 + 2];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: /* Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = mix[0];
|
||||||
|
line[x * 3 + 1] = mix[1];
|
||||||
|
line[x * 3 + 2] = mix[2];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] =
|
||||||
|
prevline[x * 3] ^ mix[0];
|
||||||
|
line[x * 3 + 1] =
|
||||||
|
prevline[x * 3 + 1] ^ mix[1];
|
||||||
|
line[x * 3 + 2] =
|
||||||
|
prevline[x * 3 + 2] ^ mix[2];
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2: /* Fill or Mix */
|
||||||
|
if (prevline == NULL)
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
{
|
||||||
|
line[x * 3] = mix[0];
|
||||||
|
line[x * 3 + 1] = mix[1];
|
||||||
|
line[x * 3 + 2] = mix[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x * 3] = 0;
|
||||||
|
line[x * 3 + 1] = 0;
|
||||||
|
line[x * 3 + 2] = 0;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
MASK_UPDATE();
|
||||||
|
if (mask & mixmask)
|
||||||
|
{
|
||||||
|
line[x * 3] =
|
||||||
|
prevline[x * 3] ^ mix [0];
|
||||||
|
line[x * 3 + 1] =
|
||||||
|
prevline[x * 3 + 1] ^ mix [1];
|
||||||
|
line[x * 3 + 2] =
|
||||||
|
prevline[x * 3 + 2] ^ mix [2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x * 3] =
|
||||||
|
prevline[x * 3];
|
||||||
|
line[x * 3 + 1] =
|
||||||
|
prevline[x * 3 + 1];
|
||||||
|
line[x * 3 + 2] =
|
||||||
|
prevline[x * 3 + 2];
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3: /* Colour */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = colour2 [0];
|
||||||
|
line[x * 3 + 1] = colour2 [1];
|
||||||
|
line[x * 3 + 2] = colour2 [2];
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 4: /* Copy */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = CVAL(input);
|
||||||
|
line[x * 3 + 1] = CVAL(input);
|
||||||
|
line[x * 3 + 2] = CVAL(input);
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 8: /* Bicolour */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
if (bicolour)
|
||||||
|
{
|
||||||
|
line[x * 3] = colour2[0];
|
||||||
|
line[x * 3 + 1] = colour2[1];
|
||||||
|
line[x * 3 + 2] = colour2[2];
|
||||||
|
bicolour = False;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
line[x * 3] = colour1[0];
|
||||||
|
line[x * 3 + 1] = colour1[1];
|
||||||
|
line[x * 3 + 2] = colour1[2];
|
||||||
|
bicolour = True;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 0xd: /* White */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = 0xff;
|
||||||
|
line[x * 3 + 1] = 0xff;
|
||||||
|
line[x * 3 + 2] = 0xff;
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
case 0xe: /* Black */
|
||||||
|
REPEAT
|
||||||
|
(
|
||||||
|
line[x * 3] = 0;
|
||||||
|
line[x * 3 + 1] = 0;
|
||||||
|
line[x * 3 + 2] = 0;
|
||||||
|
)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
unimpl("bitmap opcode 0x%x\n", opcode);
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return True;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* decompress a colour plane */
|
||||||
|
static int
|
||||||
|
process_plane(uint8 * in, int width, int height, uint8 * out, int size)
|
||||||
|
{
|
||||||
|
int indexw;
|
||||||
|
int indexh;
|
||||||
|
int code;
|
||||||
|
int collen;
|
||||||
|
int replen;
|
||||||
|
int color;
|
||||||
|
int x;
|
||||||
|
int revcode;
|
||||||
|
uint8 * last_line;
|
||||||
|
uint8 * this_line;
|
||||||
|
uint8 * org_in;
|
||||||
|
uint8 * org_out;
|
||||||
|
|
||||||
|
org_in = in;
|
||||||
|
org_out = out;
|
||||||
|
last_line = 0;
|
||||||
|
indexh = 0;
|
||||||
|
while (indexh < height)
|
||||||
|
{
|
||||||
|
out = (org_out + width * height * 4) - ((indexh + 1) * width * 4);
|
||||||
|
color = 0;
|
||||||
|
this_line = out;
|
||||||
|
indexw = 0;
|
||||||
|
if (last_line == 0)
|
||||||
|
{
|
||||||
|
while (indexw < width)
|
||||||
|
{
|
||||||
|
code = CVAL(in);
|
||||||
|
replen = code & 0xf;
|
||||||
|
collen = (code >> 4) & 0xf;
|
||||||
|
revcode = (replen << 4) | collen;
|
||||||
|
if ((revcode <= 47) && (revcode >= 16))
|
||||||
|
{
|
||||||
|
replen = revcode;
|
||||||
|
collen = 0;
|
||||||
|
}
|
||||||
|
while (collen > 0)
|
||||||
|
{
|
||||||
|
color = CVAL(in);
|
||||||
|
*out = color;
|
||||||
|
out += 4;
|
||||||
|
indexw++;
|
||||||
|
collen--;
|
||||||
|
}
|
||||||
|
while (replen > 0)
|
||||||
|
{
|
||||||
|
*out = color;
|
||||||
|
out += 4;
|
||||||
|
indexw++;
|
||||||
|
replen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while (indexw < width)
|
||||||
|
{
|
||||||
|
code = CVAL(in);
|
||||||
|
replen = code & 0xf;
|
||||||
|
collen = (code >> 4) & 0xf;
|
||||||
|
revcode = (replen << 4) | collen;
|
||||||
|
if ((revcode <= 47) && (revcode >= 16))
|
||||||
|
{
|
||||||
|
replen = revcode;
|
||||||
|
collen = 0;
|
||||||
|
}
|
||||||
|
while (collen > 0)
|
||||||
|
{
|
||||||
|
x = CVAL(in);
|
||||||
|
if (x & 1)
|
||||||
|
{
|
||||||
|
x = x >> 1;
|
||||||
|
x = x + 1;
|
||||||
|
color = -x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = x >> 1;
|
||||||
|
color = x;
|
||||||
|
}
|
||||||
|
x = last_line[indexw * 4] + color;
|
||||||
|
*out = x;
|
||||||
|
out += 4;
|
||||||
|
indexw++;
|
||||||
|
collen--;
|
||||||
|
}
|
||||||
|
while (replen > 0)
|
||||||
|
{
|
||||||
|
x = last_line[indexw * 4] + color;
|
||||||
|
*out = x;
|
||||||
|
out += 4;
|
||||||
|
indexw++;
|
||||||
|
replen--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexh++;
|
||||||
|
last_line = this_line;
|
||||||
|
}
|
||||||
|
return (int) (in - org_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 4 byte bitmap decompress */
|
||||||
|
RD_BOOL
|
||||||
|
bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size)
|
||||||
|
{
|
||||||
|
int code;
|
||||||
|
int bytes_pro;
|
||||||
|
int total_pro;
|
||||||
|
|
||||||
|
code = CVAL(input);
|
||||||
|
if (code != 0x10)
|
||||||
|
{
|
||||||
|
return False;
|
||||||
|
}
|
||||||
|
total_pro = 1;
|
||||||
|
bytes_pro = process_plane(input, width, height, output + 3, size - total_pro);
|
||||||
|
total_pro += bytes_pro;
|
||||||
|
input += bytes_pro;
|
||||||
|
bytes_pro = process_plane(input, width, height, output + 2, size - total_pro);
|
||||||
|
total_pro += bytes_pro;
|
||||||
|
input += bytes_pro;
|
||||||
|
bytes_pro = process_plane(input, width, height, output + 1, size - total_pro);
|
||||||
|
total_pro += bytes_pro;
|
||||||
|
input += bytes_pro;
|
||||||
|
bytes_pro = process_plane(input, width, height, output + 0, size - total_pro);
|
||||||
|
total_pro += bytes_pro;
|
||||||
|
return size == total_pro;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bitmap_decompress_15(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||||
|
uint8 * temp = (uint8*)malloc(input_width * input_height * 2);
|
||||||
|
RD_BOOL rv = bitmap_decompress2(temp, input_width, input_height, input, size);
|
||||||
|
|
||||||
|
// convert to rgba
|
||||||
|
for (int y = 0; y < output_height; y++) {
|
||||||
|
for (int x = 0; x < output_width; x++) {
|
||||||
|
uint16 a = ((uint16*)temp)[y * input_width + x];
|
||||||
|
uint8 r = (a & 0x7c00) >> 10;
|
||||||
|
uint8 g = (a & 0x03e0) >> 5;
|
||||||
|
uint8 b = (a & 0x001f);
|
||||||
|
r = r * 255 / 31;
|
||||||
|
g = g * 255 / 31;
|
||||||
|
b = b * 255 / 31;
|
||||||
|
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(temp);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bitmap_decompress_16(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||||
|
uint8 * temp = (uint8*)malloc(input_width * input_height * 2);
|
||||||
|
RD_BOOL rv = bitmap_decompress2(temp, input_width, input_height, input, size);
|
||||||
|
|
||||||
|
// convert to rgba
|
||||||
|
for (int y = 0; y < output_height; y++) {
|
||||||
|
for (int x = 0; x < output_width; x++) {
|
||||||
|
uint16 a = ((uint16*)temp)[y * input_width + x];
|
||||||
|
uint8 r = (a & 0xf800) >> 11;
|
||||||
|
uint8 g = (a & 0x07e0) >> 5;
|
||||||
|
uint8 b = (a & 0x001f);
|
||||||
|
r = r * 255 / 31;
|
||||||
|
g = g * 255 / 63;
|
||||||
|
b = b * 255 / 31;
|
||||||
|
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(temp);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bitmap_decompress_24(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||||
|
uint8 * temp = (uint8*)malloc(input_width * input_height * 3);
|
||||||
|
RD_BOOL rv = bitmap_decompress3(temp, input_width, input_height, input, size);
|
||||||
|
|
||||||
|
// convert to rgba
|
||||||
|
for (int y = 0; y < output_height; y++) {
|
||||||
|
for (int x = 0; x < output_width; x++) {
|
||||||
|
uint8 r = temp[(y * input_width + x) * 3];
|
||||||
|
uint8 g = temp[(y * input_width + x) * 3 + 1];
|
||||||
|
uint8 b = temp[(y * input_width + x) * 3 + 2];
|
||||||
|
((uint32*)output)[y * output_width + x] = 0xff << 24 | b << 16 | g << 8 | r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(temp);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bitmap_decompress_32(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size) {
|
||||||
|
uint8 * temp = (uint8*)malloc(input_width * input_height * 4);
|
||||||
|
RD_BOOL rv = bitmap_decompress4(temp, input_width, input_height, input, size);
|
||||||
|
|
||||||
|
// convert to rgba
|
||||||
|
for (int y = 0; y < output_height; y++) {
|
||||||
|
for (int x = 0; x < output_width; x++) {
|
||||||
|
uint8 r = temp[(y * input_width + x) * 4];
|
||||||
|
uint8 g = temp[(y * input_width + x) * 4 + 1];
|
||||||
|
uint8 b = temp[(y * input_width + x) * 4 + 2];
|
||||||
|
uint8 a = temp[(y * input_width + x) * 4 + 3];
|
||||||
|
((uint32*)output)[y * output_width + x] = 0xff << 24 | r << 16 | g << 8 | b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(temp);
|
||||||
|
|
||||||
|
return rv;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef RLE_H
|
||||||
|
#define RLE_H
|
||||||
|
|
||||||
|
#define RD_BOOL int
|
||||||
|
#define False 0
|
||||||
|
#define True 1
|
||||||
|
|
||||||
|
#define uint8 unsigned char
|
||||||
|
#define uint16 unsigned short
|
||||||
|
#define uint32 unsigned int
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RD_BOOL bitmap_decompress1(uint8 * output, int width, int height, uint8 * input, int size);
|
||||||
|
RD_BOOL bitmap_decompress2(uint8 * output, int width, int height, uint8 * input, int size);
|
||||||
|
RD_BOOL bitmap_decompress3(uint8 * output, int width, int height, uint8 * input, int size);
|
||||||
|
RD_BOOL bitmap_decompress4(uint8 * output, int width, int height, uint8 * input, int size);
|
||||||
|
|
||||||
|
//int bitmap_decompress_15(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||||
|
//int bitmap_decompress_16(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||||
|
//int bitmap_decompress_24(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||||
|
//int bitmap_decompress_32(uint8 * output, int output_width, int output_height, int input_width, int input_height, uint8* input, int size);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RLE_H
|
|
@ -0,0 +1,87 @@
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFile>
|
||||||
|
|
||||||
|
#include "thr_play.h"
|
||||||
|
#include "record_format.h"
|
||||||
|
|
||||||
|
static QString REPLAY_PATH = "E:\\work\\tp4a\\teleport\\server\\share\\replay\\rdp\\000000197\\";
|
||||||
|
|
||||||
|
|
||||||
|
ThreadPlay::ThreadPlay()
|
||||||
|
{
|
||||||
|
m_need_stop = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPlay::stop() {
|
||||||
|
m_need_stop = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadPlay::run() {
|
||||||
|
qint64 read_len = 0;
|
||||||
|
uint32_t total_pkg = 0;
|
||||||
|
|
||||||
|
QString hdr_filename(REPLAY_PATH);
|
||||||
|
hdr_filename += "tp-rdp.tpr";
|
||||||
|
|
||||||
|
QFile f_hdr(hdr_filename);
|
||||||
|
if(!f_hdr.open(QFile::ReadOnly)) {
|
||||||
|
qDebug() << "Can not open " << hdr_filename << " for read.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
update_data* dat = new update_data;
|
||||||
|
dat->data_type(TYPE_HEADER_INFO);
|
||||||
|
dat->alloc_data(sizeof(TS_RECORD_HEADER));
|
||||||
|
|
||||||
|
read_len = f_hdr.read((char*)(dat->data_buf()), dat->data_len());
|
||||||
|
if(read_len != sizeof(TS_RECORD_HEADER)) {
|
||||||
|
delete dat;
|
||||||
|
qDebug() << "invaid .tpr file.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TS_RECORD_HEADER* hdr = (TS_RECORD_HEADER*)dat->data_buf();
|
||||||
|
total_pkg = hdr->info.packages;
|
||||||
|
|
||||||
|
emit signal_update_data(dat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QString dat_filename(REPLAY_PATH);
|
||||||
|
dat_filename += "tp-rdp.dat";
|
||||||
|
|
||||||
|
QFile f_dat(dat_filename);
|
||||||
|
if(!f_dat.open(QFile::ReadOnly)) {
|
||||||
|
qDebug() << "Can not open " << dat_filename << " for read.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i < total_pkg; ++i) {
|
||||||
|
if(m_need_stop) {
|
||||||
|
qDebug() << "stop, user cancel.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TS_RECORD_PKG pkg;
|
||||||
|
read_len = f_dat.read((char*)(&pkg), sizeof(pkg));
|
||||||
|
if(read_len != sizeof(TS_RECORD_PKG)) {
|
||||||
|
qDebug() << "invaid .dat file.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_data* dat = new update_data;
|
||||||
|
dat->data_type(TYPE_DATA);
|
||||||
|
dat->alloc_data(sizeof(TS_RECORD_PKG) + pkg.size);
|
||||||
|
memcpy(dat->data_buf(), &pkg, sizeof(TS_RECORD_PKG));
|
||||||
|
read_len = f_dat.read((char*)(dat->data_buf()+sizeof(TS_RECORD_PKG)), pkg.size);
|
||||||
|
if(read_len != pkg.size) {
|
||||||
|
delete dat;
|
||||||
|
qDebug() << "invaid .dat file.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emit signal_update_data(dat);
|
||||||
|
msleep(5);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef THR_PLAY_H
|
||||||
|
#define THR_PLAY_H
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include "update_data.h"
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadPlay : public QThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
ThreadPlay();
|
||||||
|
|
||||||
|
virtual void run();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void signal_update_data(update_data*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_need_stop;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // THR_PLAY_H
|
|
@ -0,0 +1,26 @@
|
||||||
|
TEMPLATE = app
|
||||||
|
TARGET = tp-player
|
||||||
|
|
||||||
|
QT += core gui widgets
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
mainwindow.h \
|
||||||
|
thr_play.h \
|
||||||
|
update_data.h \
|
||||||
|
record_format.h \
|
||||||
|
rle.h
|
||||||
|
|
||||||
|
SOURCES += main.cpp \
|
||||||
|
mainwindow.cpp \
|
||||||
|
thr_play.cpp \
|
||||||
|
update_data.cpp \
|
||||||
|
rle.c
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
tp-player.qrc
|
||||||
|
|
||||||
|
RC_FILE += \
|
||||||
|
tp-player.rc
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
mainwindow.ui
|
|
@ -0,0 +1,7 @@
|
||||||
|
<RCC>
|
||||||
|
<qresource prefix="/tp-player">
|
||||||
|
<file>res/logo.png</file>
|
||||||
|
<file>res/bg.png</file>
|
||||||
|
<file>res/cursor.png</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,2 @@
|
||||||
|
IDI_ICON1 ICON DISCARDABLE "res\\tp-player.ico"
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include "update_data.h"
|
||||||
|
|
||||||
|
update_data::update_data(QObject *parent) : QObject(parent)
|
||||||
|
{
|
||||||
|
m_data_type = 0xff;
|
||||||
|
m_data_buf = nullptr;
|
||||||
|
m_data_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_data::~update_data() {
|
||||||
|
if(m_data_buf)
|
||||||
|
delete m_data_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_data::alloc_data(uint32_t len) {
|
||||||
|
if(m_data_buf)
|
||||||
|
delete m_data_buf;
|
||||||
|
|
||||||
|
m_data_buf = new uint8_t[len];
|
||||||
|
memset(m_data_buf, 0, len);
|
||||||
|
m_data_len = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_data::attach_data(const uint8_t* dat, uint32_t len) {
|
||||||
|
if(m_data_buf)
|
||||||
|
delete m_data_buf;
|
||||||
|
m_data_buf = new uint8_t[len];
|
||||||
|
memcpy(m_data_buf, dat, len);
|
||||||
|
m_data_len = len;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#ifndef UPDATE_DATA_H
|
||||||
|
#define UPDATE_DATA_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
class update_data : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit update_data(QObject *parent = nullptr);
|
||||||
|
virtual ~update_data();
|
||||||
|
|
||||||
|
void alloc_data(uint32_t len);
|
||||||
|
void attach_data(const uint8_t* dat, uint32_t len);
|
||||||
|
|
||||||
|
void data_type(int dt) {m_data_type = dt;}
|
||||||
|
int data_type() const {return m_data_type;}
|
||||||
|
|
||||||
|
uint8_t* data_buf() {return m_data_buf;}
|
||||||
|
uint32_t data_len() const {return m_data_len;}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_data_type;
|
||||||
|
uint8_t* m_data_buf;
|
||||||
|
uint32_t m_data_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // UPDATE_DATA_H
|
Binary file not shown.
Loading…
Reference in New Issue