Commit e1786ed9 authored by Volker Krause's avatar Volker Krause
Browse files

Add byte array API for extractor scripts

This enables converting QByteArrays to JS ArrayBuffers, and thus allows
custom binary barcode decoding also in extractor scripts.

The existing API related to byte arrays can be migrated from the barcode
API to the more appropriate place here, and more of that can be adapted
to use JS ArrayBuffers rather than opaque QByteArray variants.

First user is the MÁV barcode decoder.
parent 69f0efd3
......@@ -49,6 +49,7 @@ target_sources(KPimItinerary PRIVATE
jsapi/barcode.cpp
jsapi/bitarray.cpp
jsapi/bytearray.cpp
jsapi/jsonld.cpp
knowledgedb/alphaid.cpp
......@@ -142,6 +143,7 @@ target_link_libraries(KPimItinerary
KF5::Mime
PRIVATE
Qt::Qml
Qt::QmlPrivate
KF5::Archive
KF5::I18n
KF5::Contacts
......
......@@ -12,6 +12,7 @@
#include "logging.h"
#include "jsapi/barcode.h"
#include "jsapi/bytearray.h"
#include "jsapi/jsonld.h"
#include <QFile>
......@@ -60,6 +61,7 @@ void ExtractorScriptEngine::ensureInitialized()
d->m_engine.globalObject().setProperty(QStringLiteral("JsonLd"), d->m_engine.newQObject(d->m_jsonLdApi));
d->m_barcodeApi = new JsApi::Barcode;
d->m_engine.globalObject().setProperty(QStringLiteral("Barcode"), d->m_engine.newQObject(d->m_barcodeApi));
d->m_engine.globalObject().setProperty(QStringLiteral("ByteArray"), d->m_engine.newQObject(new JsApi::ByteArray));
d->m_watchdogThread.start();
d->m_watchdogTimer = new QTimer;
......
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "bytearray.h"
#include "logging.h"
#include <QQmlEngine>
#include <private/qv4arraybuffer_p.h>
#include <private/qv4engine_p.h>
#include <zlib.h>
using namespace KItinerary;
QJSValue JsApi::ByteArray::inflate(const QByteArray &input) const
{
QByteArray output;
output.resize(4096);
z_stream stream;
stream.zalloc = nullptr;
stream.zfree = nullptr;
stream.opaque = nullptr;
stream.avail_in = input.size();
stream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(input.data()));
stream.avail_out = output.size();
stream.next_out = reinterpret_cast<unsigned char*>(output.data());
inflateInit2(&stream, MAX_WBITS + 32);
const auto res = ::inflate(&stream, Z_NO_FLUSH);
switch (res) {
case Z_OK:
case Z_STREAM_END:
break; // all good
default:
qCWarning(Log) << "zlib decompression failed " << stream.msg << stream.avail_in;
return {};
}
inflateEnd(&stream);
output.truncate(output.size() - stream.avail_out);
return toArrayBuffer(output);
}
QString JsApi::ByteArray::decodeUtf8(const QByteArray &input) const
{
return QString::fromUtf8(input);
}
QJSValue JsApi::ByteArray::toArrayBuffer(const QByteArray &input) const
{
const auto engine = qjsEngine(this);
return QJSValue(engine->handle(), engine->handle()->newArrayBuffer(input)->asReturnedValue());
}
/*
SPDX-FileCopyrightText: 2021 Volker Krause <vkrause@kde.org>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#ifndef KITINERARY_JSAPI_BYTEARRAY_H
#define KITINERARY_JSAPI_BYTEARRAY_H
#include <QObject>
#include <QJSValue>
class QByteArray;
namespace KItinerary {
namespace JsApi {
/** API for dealing with QByteArray and/or JS ArrayBuffer objects. */
class ByteArray : public QObject
{
Q_OBJECT
public:
/** Perform zlib decompression on the given byte array.
* @returns a JS ArrayBuffer with the decompressed result.
*/
Q_INVOKABLE QJSValue inflate(const QByteArray &input) const;
/** Convert a QByteArray/ArrayBuffer to a string, assuming UTF-8 encoding. */
Q_INVOKABLE QString decodeUtf8(const QByteArray &input) const;
/** Convert a QByteArray to a JS ArrayBuffer.
* This is mainly a migration aid until we return ArrayBuffers everywhere.
*/
Q_INVOKABLE QJSValue toArrayBuffer(const QByteArray &input) const;
};
}}
#endif // KITINERARY_JSAPI_BYTEARRAY_H
......@@ -21,6 +21,19 @@ function parseTicket(pdf, node, triggerNode) {
res.reservationFor.trainNumber = trip[6];
res.reservedTicket.ticketedSeat.seatingType = trip[7];
res.reservedTicket.ticketToken = "pdf417bin:" + Barcode.toBase64(triggerNode.content);
// see https://community.kde.org/KDE_PIM/KItinerary/MAV_Barcode
const outer = ByteArray.toArrayBuffer(triggerNode.content);
const inner = ByteArray.inflate(outer.slice(2));
if (inner.byteLength >= 217) {
const view = new DataView(inner);
res.reservationFor.departureStation.identifier = "uic:" + (view.getUint32(106, false) & 0xffffff);
res.reservationFor.arrivalStation.identifier = "uic:" + (view.getUint32(109, false) & 0xffffff);
res.reservationFor.provider.identifier = "uic:" + view.getUint16(18, false);
res.reservationNumber = ByteArray.decodeUtf8(inner.slice(0, 17));
res.underName.name = ByteArray.decodeUtf8(inner.slice(39, 39 + 45));
}
reservations.push(res);
}
return reservations;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment