You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1046 lines
37 KiB

/*
SPDX-FileCopyrightText: 2007 Tobias Koenig <tokoe@kde.org>
Based on code written by Bill Janssen 2002
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qunpluck.h"
#include <QAbstractTextDocumentLayout>
#include <QDateTime>
#include <QFile>
#include <QFont>
#include <QHash>
#include <QLabel>
#include <QStack>
#include <QString>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QTextDocument>
#include <QTextFrame>
#include <QUrl>
#include <core/action.h>
#include <core/document.h>
#include "image.h"
#define GET_FUNCTION_CODE_TYPE(x) (((x) >> 3) & 0x1F)
#define GET_FUNCTION_CODE_DATALEN(x) ((x)&0x7)
#define CELLS(row, col) cells[row * cols + col]
#define READ_BIGENDIAN_SHORT(p) (((p)[0] << 8) | ((p)[1]))
#define READ_BIGENDIAN_LONG(p) (((p)[0] << 24) | ((p)[1] << 16) | ((p)[2] << 8) | ((p)[3]))
/*
static void LinkRecords
(
char* dir
)
{
RecordNode* ptr;
char* realfilename;
char* linkname;
realfilename = (char*)malloc (strlen (dir) + 20);
linkname = (char*)malloc (strlen (dir) + 20);
for (ptr = records; ptr != NULL; ptr = ptr->next) {
if (ptr->page_id != ptr->index) {
sprintf (realfilename, "%s/r%d.html", dir, ptr->page_id);
sprintf (linkname, "%s/r%d.html", dir, ptr->index);
link (realfilename, linkname);
}
}
free (realfilename);
free (linkname);
}
*/
class Context
{
public:
int recordId;
QTextDocument *document;
QTextCursor *cursor;
QStack<QTextCharFormat> stack;
QList<int> images;
QString linkUrl;
int linkStart;
int linkPage;
};
class RecordNode
{
public:
int index;
int page_id;
bool done;
};
static Okular::DocumentViewport calculateViewport(QTextDocument *document, const QTextBlock &block)
{
if (!block.isValid()) {
return Okular::DocumentViewport();
}
const QRectF rect = document->documentLayout()->blockBoundingRect(block);
const QSizeF size = document->size();
int page = qRound(rect.y()) / qRound(size.height());
Okular::DocumentViewport viewport(page);
viewport.rePos.normalizedX = (double)rect.x() / (double)size.width();
viewport.rePos.normalizedY = (double)rect.y() / (double)size.height();
viewport.rePos.enabled = true;
viewport.rePos.pos = Okular::DocumentViewport::Center;
return viewport;
}
QUnpluck::QUnpluck()
: mDocument(nullptr)
{
}
QUnpluck::~QUnpluck()
{
mLinks.clear();
mNamedTargets.clear();
mPages.clear();
}
bool QUnpluck::open(const QString &fileName)
{
mLinks.clear();
mNamedTargets.clear();
mPages.clear();
mDocument = plkr_OpenDBFile(QFile::encodeName(fileName).data());
if (!mDocument) {
mErrorString = QObject::tr("Unable to open document");
return false;
}
// bool status = true;
mInfo.insert(QStringLiteral("name"), QString::fromLocal8Bit(plkr_GetName(mDocument)));
mInfo.insert(QStringLiteral("title"), QString::fromLocal8Bit(plkr_GetTitle(mDocument)));
mInfo.insert(QStringLiteral("author"), QString::fromLocal8Bit(plkr_GetAuthor(mDocument)));
mInfo.insert(QStringLiteral("time"), QDateTime::fromSecsSinceEpoch(plkr_GetPublicationTime(mDocument)).toString());
AddRecord(plkr_GetHomeRecordID(mDocument));
int number = GetNextRecordNumber();
while (number > 0) {
/*status = */ TranscribeRecord(number);
number = GetNextRecordNumber();
}
// Iterate over all records again to add those which aren't linked directly
for (int i = 1; i < plkr_GetRecordCount(mDocument); ++i) {
AddRecord(plkr_GetUidForIndex(mDocument, i));
}
number = GetNextRecordNumber();
while (number > 0) {
/*status = */ TranscribeRecord(number);
number = GetNextRecordNumber();
}
for (int i = 0; i < mRecords.count(); ++i) {
delete mRecords[i];
}
mRecords.clear();
plkr_CloseDoc(mDocument);
/**
* Calculate hash map
*/
QHash<int, int> pageHash;
for (int i = 0; i < mContext.count(); ++i) {
pageHash.insert(mContext[i]->recordId, i);
}
/**
* Convert ids
*/
for (int i = 0; i < mContext.count(); ++i) {
Context *context = mContext[i];
for (int j = 0; j < context->images.count(); ++j) {
int imgNumber = context->images[j];
context->document->addResource(QTextDocument::ImageResource, QUrl(QStringLiteral("%1.jpg").arg(imgNumber)), mImages[imgNumber]);
}
mPages.append(context->document);
}
qDeleteAll(mContext);
mContext.clear();
// convert record_id into page
for (int i = 0; i < mLinks.count(); ++i) {
mLinks[i].page = pageHash[mLinks[i].page];
if (mLinks[i].url.startsWith(QLatin1String("page:"))) {
int page = mLinks[i].url.midRef(5).toInt();
Okular::DocumentViewport viewport(pageHash[page]);
viewport.rePos.normalizedX = 0;
viewport.rePos.normalizedY = 0;
viewport.rePos.enabled = true;
viewport.rePos.pos = Okular::DocumentViewport::TopLeft;
mLinks[i].link = new Okular::GotoAction(QString(), viewport);
} else if (mLinks[i].url.startsWith(QLatin1String("para:"))) {
QPair<int, QTextBlock> data = mNamedTargets[mLinks[i].url];
QTextDocument *document = mPages[mLinks[i].page];
Okular::DocumentViewport viewport = calculateViewport(document, data.second);
mLinks[i].link = new Okular::GotoAction(QString(), viewport);
} else {
mLinks[i].link = new Okular::BrowseAction(QUrl(mLinks[i].url));
}
}
return true;
}
int QUnpluck::GetNextRecordNumber()
{
int index = 0;
for (int pos = 0; pos < mRecords.count(); ++pos) {
if (!mRecords[pos]->done) {
index = mRecords[pos]->index;
break;
}
}
return index;
}
int QUnpluck::GetPageID(int index)
{
for (int pos = 0; pos < mRecords.count(); ++pos) {
if (mRecords[pos]->index == index) {
return mRecords[pos]->page_id;
}
}
return 0;
}
void QUnpluck::AddRecord(int index)
{
for (int pos = 0; pos < mRecords.count(); ++pos) {
if (mRecords[pos]->index == index) {
return;
}
}
RecordNode *node = new RecordNode;
node->done = false;
node->index = index;
node->page_id = index;
mRecords.append(node);
}
void QUnpluck::MarkRecordDone(int index)
{
for (int pos = 0; pos < mRecords.count(); ++pos) {
if (mRecords[pos]->index == index) {
mRecords[pos]->done = true;
return;
}
}
AddRecord(index);
MarkRecordDone(index);
}
void QUnpluck::SetPageID(int index, int page_id)
{
for (int pos = 0; pos < mRecords.count(); ++pos) {
if (mRecords[pos]->index == index) {
mRecords[pos]->page_id = page_id;
return;
}
}
AddRecord(index);
SetPageID(index, page_id);
}
QString QUnpluck::MailtoURLFromBytes(unsigned char *record_data)
{
unsigned char *bytes = record_data + 8;
int to_offset = (bytes[0] << 8) + bytes[1];
int cc_offset = (bytes[2] << 8) + bytes[3];
int subject_offset = (bytes[4] << 8) + bytes[5];
int body_offset = (bytes[6] << 8) + bytes[7];
QString url(QStringLiteral("mailto:"));
if (to_offset != 0) {
url += QString::fromLatin1((char *)(bytes + to_offset));
}
if ((cc_offset != 0) || (subject_offset != 0) || (body_offset != 0)) {
url += QLatin1String("?");
}
if (cc_offset != 0) {
url += QLatin1String("cc=") + QString::fromLatin1((char *)(bytes + cc_offset));
}
if (subject_offset != 0) {
url += QLatin1String("subject=") + QString::fromLatin1((char *)(bytes + subject_offset));
}
if (body_offset != 0) {
url += QLatin1String("body=") + QString::fromLatin1((char *)(bytes + body_offset));
}
return url;
}
QImage QUnpluck::TranscribeImageRecord(unsigned char *bytes)
{
QImage image;
TranscribePalmImageToJPEG(bytes + 8, image);
return image;
}
void QUnpluck::DoStyle(Context *context, int style, bool start)
{
if (start) {
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
int pointSize = qRound(format.fontPointSize());
switch (style) {
case 1:
format.setFontWeight(QFont::Bold);
pointSize += 3;
break;
case 2:
format.setFontWeight(QFont::Bold);
pointSize += 2;
break;
case 3:
format.setFontWeight(QFont::Bold);
pointSize += 1;
break;
case 4:
format.setFontWeight(QFont::Bold);
break;
case 5:
format.setFontWeight(QFont::Bold);
pointSize += -1;
break;
case 6:
format.setFontWeight(QFont::Bold);
pointSize += -2;
break;
case 7:
format.setFontWeight(QFont::Bold);
break;
case 8:
format.setFontFamily(QStringLiteral("Courier New,courier"));
break;
}
format.setFontPointSize(qMax(pointSize, 1));
context->cursor->setCharFormat(format);
} else {
if (!context->stack.isEmpty()) {
context->cursor->setCharFormat(context->stack.pop());
}
}
}
void QUnpluck::ParseText(plkr_Document *doc, unsigned char *ptr, int text_len, int *font, int *style, Context *context)
{
unsigned char *end;
int fctype;
int fclen;
end = ptr + text_len;
while (ptr < end) {
if (ptr[0]) {
context->cursor->insertText(QString::fromLocal8Bit((char *)ptr));
ptr += strlen((char *)ptr);
} else {
fctype = GET_FUNCTION_CODE_TYPE(ptr[1]);
fclen = 2 + GET_FUNCTION_CODE_DATALEN(ptr[1]);
switch (fctype) {
case PLKR_TFC_LINK:
switch (fclen) {
case 4: /* ANCHOR_BEGIN */
{
int record_id = (ptr[2] << 8) + ptr[3];
/** TODO:
plkr_DataRecordType type =
(plkr_DataRecordType)plkr_GetRecordType (doc, record_id);
if (type ==
PLKR_DRTYPE_IMAGE
|| type ==
PLKR_DRTYPE_IMAGE_COMPRESSED)
output += QString( "<A HREF=\"r%1.jpg\">" ).arg(record_id);
else
output += QString( "<A HREF=\"r%1.html\">" ).arg(record_id);
*/
AddRecord(record_id);
} break;
case 2: /* ANCHOR_END */
// TODO: output += QString( "</A>" );
break;
}
ptr += fclen;
break;
case PLKR_TFC_FONT:
DoStyle(context, *style, false);
*style = ptr[2];
DoStyle(context, *style, true);
ptr += fclen;
break;
case PLKR_TFC_NEWLINE: {
// TODO: remove the setCharFormat when Qt is fixed
QTextCharFormat format(context->cursor->charFormat());
context->cursor->insertText(QStringLiteral("\n"));
context->cursor->setCharFormat(format);
ptr += fclen;
break;
}
case PLKR_TFC_BITALIC: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontItalic(true);
context->cursor->setCharFormat(format);
ptr += fclen;
break;
}
case PLKR_TFC_EITALIC: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontItalic(false);
context->cursor->setCharFormat(format);
ptr += fclen;
break;
}
case PLKR_TFC_COLOR:
if (*font) {
(*font)--;
if (!context->stack.isEmpty()) {
context->cursor->setCharFormat(context->stack.pop());
}
}
{
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
format.setForeground(QColor((ptr[2] << 16), (ptr[3] << 8), ptr[4]));
context->cursor->setCharFormat(format);
}
(*font)++;
ptr += fclen;
break;
case PLKR_TFC_BULINE: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontUnderline(true);
context->cursor->setCharFormat(format);
ptr += fclen;
} break;
case PLKR_TFC_EULINE: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontUnderline(false);
context->cursor->setCharFormat(format);
ptr += fclen;
} break;
case PLKR_TFC_BSTRIKE: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontStrikeOut(true);
context->cursor->setCharFormat(format);
ptr += fclen;
break;
}
case PLKR_TFC_ESTRIKE: {
QTextCharFormat format(context->cursor->charFormat());
format.setFontStrikeOut(false);
context->cursor->setCharFormat(format);
ptr += fclen;
break;
}
case PLKR_TFC_TABLE:
if (fclen == 4) {
int record_id, datalen;
plkr_DataRecordType type = (plkr_DataRecordType)0;
unsigned char *bytes = nullptr;
record_id = (ptr[2] << 8) + ptr[3];
bytes = plkr_GetRecordBytes(doc, record_id, &datalen, &type);
TranscribeTableRecord(doc, context, bytes);
}
ptr += fclen;
break;
default:
ptr += fclen;
}
}
}
}
bool QUnpluck::TranscribeTableRecord(plkr_Document *doc, Context *context, unsigned char *bytes)
{
unsigned char *ptr = &bytes[24];
unsigned char *end;
// char* align_names[] = { "left", "right", "center" };
// bool in_row = false;
// int cols;
int size;
// int rows;
// int border;
int record_id;
// int align;
int text_len;
// int colspan;
// int rowspan;
int font = 0;
int style = 0;
int fctype;
int fclen;
// long border_color;
// long link_color;
size = (bytes[8] << 8) + bytes[9];
// cols = (bytes[10] << 8) + bytes[11];
// rows = (bytes[12] << 8) + bytes[13];
// border = bytes[15];
// border_color = (bytes[17] << 16) + (bytes[18] << 8) + (bytes[19] << 8);
// link_color = (bytes[21] << 16) + (bytes[22] << 8) + (bytes[23] << 8);
end = ptr + size - 1;
/**
output += QString( "<TABLE border=%1 bordercolor=\"#%2\" "
"linkcolor=\"#%3\">\n" ).arg(border, border_color, link_color);
*/
while (ptr < end) {
if (ptr[0] == '\0') {
fctype = GET_FUNCTION_CODE_TYPE(ptr[1]);
fclen = 2 + GET_FUNCTION_CODE_DATALEN(ptr[1]);
switch (fctype) {
case PLKR_TFC_TABLE:
switch (fclen) {
case 2: /* NEW_ROW */
/*
if (in_row)
output += QString( "</TR>\n" );
output += QString( "<TR>\n" );
in_row = true;
*/
ptr += fclen;
break;
case 9: /* NEW_CELL */
// align = ptr[2];
// colspan = ptr[5];
// rowspan = ptr[6];
/**
output += QString( "<TD align=\"%1\" colspan=%2 "
"rowspan=%3 bordercolor=\"#\">" ).arg(
align_names[align], colspan, rowspan );
// border_color);
*/
if ((record_id = READ_BIGENDIAN_SHORT(&ptr[3]))) {
QTextCharFormat format = context->cursor->charFormat();
context->cursor->insertImage(QStringLiteral("%1.jpg").arg(record_id));
context->cursor->setCharFormat(format);
context->images.append(record_id);
AddRecord(record_id);
}
DoStyle(context, style, true);
text_len = READ_BIGENDIAN_SHORT(&ptr[7]);
ptr += fclen;
ParseText(doc, ptr, text_len, &font, &style, context);
ptr += text_len;
DoStyle(context, style, false);
// output += QString( "</TD>\n" );
break;
default:
ptr += fclen;
}
break;
default:
ptr += fclen;
}
} else {
// output += QString( "</TABLE>\n" );
return false;
}
}
// output += QString( "</TABLE>\n" );
return true;
}
typedef struct {
int size;
int attributes;
} ParagraphInfo;
static ParagraphInfo *ParseParagraphInfo(unsigned char *bytes, int *nparas)
{
ParagraphInfo *paragraph_info;
int j;
int n;
n = (bytes[2] << 8) + bytes[3];
paragraph_info = (ParagraphInfo *)malloc(sizeof(ParagraphInfo) * n);
for (j = 0; j < n; j++) {
paragraph_info[j].size = (bytes[8 + (j * 4) + 0] << 8) + bytes[8 + (j * 4) + 1];
paragraph_info[j].attributes = (bytes[8 + (j * 4) + 2] << 8) + bytes[8 + (j * 4) + 3];
}
*nparas = n;
return paragraph_info;
}
bool QUnpluck::TranscribeTextRecord(plkr_Document *doc, int id, Context *context, unsigned char *bytes, plkr_DataRecordType type)
{
unsigned char *ptr;
unsigned char *run;
unsigned char *para_start;
unsigned char *data;
unsigned char *start;
ParagraphInfo *paragraphs;
bool first_record_of_page = true;
bool current_link;
bool current_italic;
bool current_struckthrough;
bool current_underline;
int fctype;
int fclen;
int para_index;
int para_len;
int textlen;
int data_len;
int current_font;
int record_index;
// int current_alignment;
// int current_left_margin;
// int current_right_margin;
int nparagraphs;
// long current_color;
record_index = id;
paragraphs = ParseParagraphInfo(bytes, &nparagraphs);
start = bytes + 8 + ((bytes[2] << 8) + bytes[3]) * 4;
for (para_index = 0, ptr = start, run = start; para_index < nparagraphs; para_index++) {
para_len = paragraphs[para_index].size;
/* If the paragraph is the last in the record, and it consists
of a link to the next record in the logical page, we trim off
the paragraph and instead insert the whole page */
if (((para_index + 1) == nparagraphs) && (para_len == (sizeof("Click here for the next part") + 5)) && (*ptr == 0) && (ptr[1] == ((PLKR_TFC_LINK << 3) + 2)) && (strcmp((char *)(ptr + 4), "Click here for the next part") == 0)) {
record_index = (ptr[2] << 8) + ptr[3];
if ((data = plkr_GetRecordBytes(doc, record_index, &data_len, &type)) == nullptr) {
// ShowWarning ("Can't open record %d!", record_index);
free(paragraphs);
return false;
} else if (!(type == PLKR_DRTYPE_TEXT_COMPRESSED || type == PLKR_DRTYPE_TEXT)) {
// ShowWarning ("Bad record type %d in record linked from end of record %d", type, id);
free(paragraphs);
return false;
}
first_record_of_page = false;
para_index = 0;
ptr = data + 8 + ((data[2] << 8) + data[3]) * 4;
run = ptr;
free(paragraphs);
paragraphs = ParseParagraphInfo(data, &nparagraphs);
para_len = paragraphs[para_index].size;
MarkRecordDone(record_index);
SetPageID(record_index, id);
}
if ((para_index == 0) && !first_record_of_page && (*ptr == 0) && (ptr[1] == ((PLKR_TFC_LINK << 3) + 2)) && (strcmp((char *)(ptr + 4), "Click here for the previous part") == 0)) {
/* throw away this inserted paragraph */
ptr += para_len;
run = ptr;
continue;
}
QTextCharFormat format(context->cursor->charFormat());
QTextBlockFormat blockFormat(context->cursor->blockFormat());
blockFormat.setAlignment(Qt::AlignLeft);
context->cursor->insertBlock(blockFormat);
context->cursor->setCharFormat(format);
mNamedTargets.insert(QStringLiteral("para:%1-%2").arg(record_index).arg(para_index), QPair<int, QTextBlock>(GetPageID(record_index), context->cursor->block()));
current_link = false;
/* at the beginning of a paragraph, we start with a clean graphics context */
current_font = 0;
// current_alignment = 0;
// current_color = 0;
current_italic = false;
current_underline = false;
current_struckthrough = false;
// current_left_margin = 0;
// current_right_margin = 0;
for (para_start = ptr, textlen = 0; (ptr - para_start) < para_len;) {
if (*ptr == 0) {
/* function code */
if ((ptr - run) > 0) {
/* write out any pending text */
context->cursor->insertText(QString::fromLatin1((char *)run, ptr - run));
textlen += (ptr - run);
}
ptr++;
fctype = GET_FUNCTION_CODE_TYPE(*ptr);
fclen = GET_FUNCTION_CODE_DATALEN(*ptr);
ptr++;
if (fctype == PLKR_TFC_NEWLINE) {
// TODO: remove the setCharFormat when Qt is fixed
QTextCharFormat format(context->cursor->charFormat());
context->cursor->insertText(QStringLiteral("\n"));
context->cursor->setCharFormat(format);
} else if (fctype == PLKR_TFC_LINK) {
int record_id, real_record_id, datalen;
plkr_DataRecordType type = (plkr_DataRecordType)0;
unsigned char *bytes = nullptr;
char *url = nullptr;
if (fclen == 0) {
if (current_link) {
if (!context->stack.isEmpty()) {
context->cursor->setCharFormat(context->stack.pop());
}
if (!context->linkUrl.isEmpty()) {
Link link;
link.url = context->linkUrl;
link.start = context->linkStart;
link.end = context->cursor->position();
link.page = GetPageID(id);
mLinks.append(link);
}
}
current_link = false;
} else {
record_id = (ptr[0] << 8) + ptr[1];
bytes = plkr_GetRecordBytes(doc, record_id, &datalen, &type);
if (!bytes) {
url = plkr_GetRecordURL(doc, record_id);
}
if (bytes && (type == PLKR_DRTYPE_MAILTO)) {
context->linkUrl = MailtoURLFromBytes(bytes);
context->linkStart = context->cursor->position();
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
format.setForeground(Qt::blue);
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
context->cursor->setCharFormat(format);
current_link = true;
} else if (!bytes && url) {
context->linkUrl = QString::fromLatin1(url);
context->linkStart = context->cursor->position();
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
format.setForeground(Qt::blue);
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
context->cursor->setCharFormat(format);
current_link = true;
} else if (bytes && (fclen == 2)) {
AddRecord(record_id);
real_record_id = GetPageID(record_id);
if (type == PLKR_DRTYPE_IMAGE || type == PLKR_DRTYPE_IMAGE_COMPRESSED) {
context->linkUrl = QStringLiteral("%1.jpg").arg(record_id);
context->linkStart = context->cursor->position();
} else {
context->linkUrl = QStringLiteral("page:%1").arg(real_record_id);
context->linkStart = context->cursor->position();
}
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
format.setForeground(Qt::blue);
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
context->cursor->setCharFormat(format);
current_link = true;
} else if (bytes && (fclen == 4)) {
AddRecord(record_id);
context->linkUrl = QStringLiteral("para:%1-%2").arg(record_id).arg((ptr[2] << 8) + ptr[3]);
context->linkStart = context->cursor->position();
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
format.setForeground(Qt::blue);
format.setUnderlineStyle(QTextCharFormat::SingleUnderline);
context->cursor->setCharFormat(format);
current_link = true;
} else {
// ShowWarning("odd link found: record_id=%d, bytes=0x%p, type=%d, url=%s", record_id, bytes, type, (url ? url : "0x0"));
}
}
} else if (fctype == PLKR_TFC_FONT) {
if (current_font != *ptr) {
if (!context->stack.isEmpty()) {
context->cursor->setCharFormat(context->stack.pop());
}
QTextCharFormat format(context->cursor->charFormat());
context->stack.push(format);
int pointSize = qRound(format.fontPointSize());
if (*ptr == 1) {
format.setFontWeight(QFont::Bold);
pointSize += 3;
} else if (*ptr == 2) {
format.setFontWeight(QFont::Bold);
pointSize += 2;
} else if (*ptr == 3) {
format.setFontWeight(QFont::Bold);
pointSize += 1;
} else if (*ptr == 4) {
format.setFontWeight(QFont::Bold);
} else if (*ptr == 5) {
format.setFontWeight(QFont::Bold);
pointSize += -1;
} else if (*ptr == 6) {
format.setFontWeight(QFont::Bold);
pointSize += -2;
} else if (*ptr == 7) {
format.setFontWeight(QFont::Bold);
} else if (*ptr == 8) {
format.setFontFamily(QStringLiteral("Courier New,courier"));
} else if (*ptr == 11) {
format.setVerticalAlignment(QTextCharFormat::AlignSuperScript);
}
format.setFontPointSize(qMax(pointSize, 1));
context->cursor->setCharFormat(format);
current_font = *ptr;
}
} else if (fctype == PLKR_TFC_BITALIC) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontItalic(true);
context->cursor->setCharFormat(format);
current_italic = true;
} else if (fctype == PLKR_TFC_EITALIC) {
if (current_italic) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontItalic(false);
context->cursor->setCharFormat(format);
current_italic = false;
}
} else if (fctype == PLKR_TFC_BULINE) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontUnderline(true);
context->cursor->setCharFormat(format);
current_underline = true;
} else if (fctype == PLKR_TFC_EULINE) {
if (current_underline) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontUnderline(false);
context->cursor->setCharFormat(format);
current_underline = false;
}
} else if (fctype == PLKR_TFC_BSTRIKE) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontStrikeOut(true);
context->cursor->setCharFormat(format);
current_struckthrough = true;
} else if (fctype == PLKR_TFC_ESTRIKE) {
if (current_struckthrough) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontStrikeOut(false);
context->cursor->setCharFormat(format);
current_struckthrough = false;
}
} else if (fctype == PLKR_TFC_HRULE) {
QTextCharFormat charFormat = context->cursor->charFormat();
QTextBlockFormat oldBlockFormat = context->cursor->blockFormat();
QTextBlockFormat blockFormat;
blockFormat.setProperty(QTextFormat::BlockTrailingHorizontalRulerWidth, QStringLiteral("100%"));
context->cursor->insertBlock(blockFormat);
context->cursor->insertBlock(oldBlockFormat);
context->cursor->setCharFormat(charFormat);
} else if (fctype == PLKR_TFC_ALIGN) {
// current_alignment = 0;
if (*ptr < 4) {
QTextBlockFormat format(context->cursor->blockFormat());
if (*ptr == 0) {
format.setAlignment(Qt::AlignLeft);
} else if (*ptr == 1) {
format.setAlignment(Qt::AlignRight);
} else if (*ptr == 2) {
format.setAlignment(Qt::AlignCenter);
} else if (*ptr == 3) {
format.setAlignment(Qt::AlignJustify);
}
QTextCharFormat charFormat(context->cursor->charFormat());
context->cursor->insertBlock(format);
context->cursor->setCharFormat(charFormat);
// current_alignment = (*ptr) + 1;
}
} else if (fctype == PLKR_TFC_COLOR) {
/* not sure what to do here yet */
/*
fprintf (fp, "<!-- color=\"#%02x%02x%02x\" -->",
ptr[0], ptr[1], ptr[2]);*/
// current_color =
// (ptr[0] << 16) + (ptr[1] << 8) + ptr[2];
} else if (fctype == PLKR_TFC_IMAGE || fctype == PLKR_TFC_IMAGE2) {
QTextCharFormat format = context->cursor->charFormat();
context->cursor->insertImage(QStringLiteral("%1.jpg").arg((ptr[0] << 8) + ptr[1]));
context->images.append((ptr[0] << 8) + ptr[1]);
context->cursor->setCharFormat(format);
AddRecord((ptr[0] << 8) + ptr[1]);
} else if (fctype == PLKR_TFC_TABLE) {
int record_id, datalen;
plkr_DataRecordType type = (plkr_DataRecordType)0;
unsigned char *bytes = nullptr;
record_id = (ptr[0] << 8) + ptr[1];
bytes = plkr_GetRecordBytes(doc, record_id, &datalen, &type);
TranscribeTableRecord(doc, context, bytes);
} else if (fctype == PLKR_TFC_UCHAR) {
if (fclen == 3) {
context->cursor->insertText(QChar((ptr[1] << 8) + ptr[2]));
} else if (fclen == 5) {
context->cursor->insertText(QChar((ptr[3] << 8) + ptr[4]));
}
/* skip over alternate text */
ptr += ptr[0];
}
ptr += fclen;
run = ptr;
} else {
ptr++;
}
}
if ((ptr - run) > 0) {
/* output any pending text at the end of the paragraph */
context->cursor->insertText(QString::fromLatin1((char *)run, ptr - run));
textlen += (ptr - run);
run = ptr;
}
/* clear the graphics state again */
if (current_font > 0 && current_font < 9) {
if (!context->stack.isEmpty()) {
context->cursor->setCharFormat(context->stack.pop());
}
}
if (current_italic) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontItalic(false);
context->cursor->setCharFormat(format);
}
if (current_underline) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontUnderline(false);
context->cursor->setCharFormat(format);
}
if (current_struckthrough) {
QTextCharFormat format(context->cursor->charFormat());
format.setFontStrikeOut(false);
context->cursor->setCharFormat(format);
}
}
free(paragraphs);
return true;
}
bool QUnpluck::TranscribeRecord(int index)
{
plkr_DataRecordType type;
int data_len;
bool status = true;
unsigned char *data = plkr_GetRecordBytes(mDocument, index, &data_len, &type);
if (!data) {
MarkRecordDone(index);
return false;
}
if (type == PLKR_DRTYPE_TEXT_COMPRESSED || type == PLKR_DRTYPE_TEXT) {
QTextDocument *document = new QTextDocument;
QTextFrameFormat format(document->rootFrame()->frameFormat());
format.setMargin(20);
document->rootFrame()->setFrameFormat(format);
Context *context = new Context;
context->recordId = index;
context->document = document;
context->cursor = new QTextCursor(document);
QTextCharFormat charFormat;
charFormat.setFontPointSize(10);
charFormat.setFontFamily(QStringLiteral("Helvetica"));
context->cursor->setCharFormat(charFormat);
status = TranscribeTextRecord(mDocument, index, context, data, type);
document->setTextWidth(600);
delete context->cursor;
mContext.append(context);
} else if (type == PLKR_DRTYPE_IMAGE_COMPRESSED || type == PLKR_DRTYPE_IMAGE) {
QImage image = TranscribeImageRecord(data);
mImages.insert(index, image);
} else if (type == PLKR_DRTYPE_MULTIIMAGE) {
QImage image;
if (TranscribeMultiImageRecord(mDocument, image, data)) {
mImages.insert(index, image);
}
} else {
status = false;
}
// plkr_GetHomeRecordID (doc)))
MarkRecordDone(index);
return status;
}