Loading...
Searching...
No Matches
binarydataarray.cpp
Go to the documentation of this file.
/**
* \file pappsomspp/core/processing/cbor/mzcbor/binarydataarray.cpp
* \date 25/11/2025
* \author Olivier Langella
* \brief PSI BinaryDataArray object for mzML/mzCBOR
*/
/*******************************************************************************
* Copyright (c) 2025 Olivier Langella <Olivier.Langella@universite-paris-saclay.fr>.
*
* This file is part of PAPPSOms-tools.
*
* PAPPSOms-tools 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.
*
* PAPPSOms-tools 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 PAPPSOms-tools. If not, see <http://www.gnu.org/licenses/>.
*
******************************************************************************/
#include "binarydataarray.h"
#include "cvparam.h"
#include "pappsomspp/core/pappsoexception.h"
#include <qjsonarray.h>
#include <qlogging.h>
#include <zlib.h>
void
pappso::cbor::mzcbor::BinaryDataArray::fromCbor(CborStreamReader &reader)
{
QString txt_value;
reader.enterContainer();
// qDebug() << txt_value;
while(reader.hasNext() && (!reader.isInvalid()))
{
if(reader.isString())
{
if(reader.decodeString(txt_value))
{
// qDebug() << txt_value;
if(txt_value == "bits")
{
// cvParamMap = CvParam::getCvParamsMapFromCbor(reader);
bits = reader.toUnsignedInteger();
reader.next();
}
else if(txt_value == "isInt")
{
// cvParamMap = CvParam::getCvParamsMapFromCbor(reader);
isInt = reader.toBool();
reader.next();
}
else if(txt_value == "unit")
{
// cvParamMap = CvParam::getCvParamsMapFromCbor(reader);
reader.decodeString(txt_value);
unit = txt_value;
}
else if(txt_value == "compress")
{
// cvParamMap = CvParam::getCvParamsMapFromCbor(reader);
reader.decodeString(txt_value);
compress = txt_value;
}
else if(txt_value == "data")
{
// cvParamMap = CvParam::getCvParamsMapFromCbor(reader);
// reader.next();
// qDebug() << reader.type();
auto r = reader.readByteArray();
while(r.status == QCborStreamReader::Ok)
{
byteArray += r.data;
r = reader.readByteArray();
}
if(r.status == QCborStreamReader::Error)
{
// handle error condition
// qDebug() << "error";
byteArray.clear();
}
}
else
{
reader.next();
}
}
else
{
reader.next();
}
}
else
{
reader.next();
}
}
reader.leaveContainer();
}
void
pappso::cbor::mzcbor::BinaryDataArray::toCbor(CborStreamWriter &writer)
{
writer.startMap();
writer.append("unit");
writer.append(unit);
writer.append("bits");
writer.append(bits);
writer.append("isInt");
writer.append(isInt);
writer.append("compress");
writer.append(compress);
writer.append("data");
writer.append(byteArray);
writer.endMap();
}
void
pappso::cbor::mzcbor::BinaryDataArray::fromMzml(QXmlStreamReader &reader)
{
qDebug();
//<binaryDataArray encodedLength="6380">
std::size_t encodedLength = reader.attributes().value("encodedLength").toULongLong();
qDebug() << "encodedLength=" << encodedLength;
while(reader.readNext() && !reader.isEndElement())
{
if(reader.isStartElement())
{
if(reader.name().toString() == "cvParam")
{
QString accession = reader.attributes().value("accession").toString();
qDebug() << "accession=" << accession;
//<cvParam cvRef="MS" accession="MS:1000523" value="" name="64-bit float" />
if(accession == "MS:1000523")
{
bits = 64;
isInt = false;
}
else if(accession == "MS:1000519")
{
/*
*
[Term]
id: MS:1000519
name: 32-bit integer
def: "Signed 32-bit little-endian integer." [PSI:MS]
is_a: MS:1000518 ! binary data type
*/
bits = 32;
isInt = true;
}
else if(accession == "MS:1000521")
{
/*
[Term]
id: MS:1000521
name: 32-bit float
def: "32-bit precision little-endian floating point conforming to IEEE-754." [PSI:MS]
is_a: MS:1000518 ! binary data type
*/
bits = 32;
isInt = false;
}
else if(accession == "MS:1000522")
{
/*
[Term]
id: MS:1000522
name: 64-bit integer
def: "Signed 64-bit little-endian integer." [PSI:MS]
is_a: MS:1000518 ! binary data type*/
bits = 64;
isInt = true;
}
//<cvParam cvRef="MS" accession="MS:1000574" value="" name="zlib compression" />
else if(accession == "MS:1000574")
{
compress = "zlib";
}
else if(accession == "MS:1000576")
{
/*
[Term]
id: MS:1000576
name: no compression
def: "No Compression." [PSI:MS]
is_a: MS:1000572 ! binary data compression type
*/
compress = "none";
}
else if(accession == "MS:1000515")
{
unit = accession;
}
else if(accession == "MS:1000514")
{
// <cvParam cvRef="MS" accession="MS:1000514" value="" name="m/z array"
// unitAccession="MS:1000040" unitName="m/z" unitCvRef="MS" />
unit = accession;
}
else if(accession == "MS:1000595")
{
// <cvParam cvRef="MS" accession="MS:1000595" name="time array" value=""
// unitCvRef="UO" unitAccession="UO:0000031" unitName="minute"/>
unit = accession;
}
else if(accession == "MS:1000786")
{
// <cvParam cvRef="MS" accession="MS:1000786" name="non-standard data
// array" value="ms level" unitCvRef="UO" unitAccession="UO:0000186"
// unitName="dimensionless unit"/>
//
unit = accession;
}
else
{
reader.raiseError(
QObject::tr("cvParam accession %1 is not known in binaryDataArray")
.arg(accession));
throw pappso::PappsoException(
QObject::tr("cvParam accession %1 is not known in binaryDataArray")
.arg(accession));
}
reader.skipCurrentElement();
}
else if(reader.name().toString() == "binary")
{
while(reader.readNext() && !reader.isEndElement())
{
if(reader.isCharacters())
{
// clean content:
QStringView content = reader.text().trimmed();
if((reader.text().toString() == "\n") || (reader.text().toString() == "\n\t"))
{
}
else
{
// text node
if(!content.isEmpty())
{
// qDebug() << "text isCharacters" << content.mid(0, 10);
if((std::size_t)reader.text().size() != encodedLength)
{
qWarning() << "reader.text().size() != encodedLength"
<< reader.text().size() << " " << encodedLength;
}
// mp_cborWriter->append("@text@");
// mp_cborWriter->append(content);
byteArray = byteArray.fromBase64(reader.text().trimmed().toLatin1());
}
}
}
}
}
else
{
reader.skipCurrentElement();
}
}
}
qDebug();
}
void
pappso::cbor::mzcbor::BinaryDataArray::toMzml(QXmlStreamWriter &writer)
{
//<binaryDataArray encodedLength="1152">
writer.writeStartElement("binaryDataArray");
auto base64 = byteArray.toBase64();
writer.writeAttribute("encodedLength", QString("%1").arg(base64.size()));
// <cvParam cvRef="MS" accession="MS:1000514" value="" name="m/z array"
// unitAccession="MS:1000040" unitName="m/z" unitCvRef="MS" />
CvParam cv_param;
cv_param.cvRef = "MS";
if(unit == "MS:1000514")
{
cv_param.accession = unit;
cv_param.name = "m/z array";
cv_param.unitCvRef = "MS";
cv_param.unitAccession = "MS:1000040";
cv_param.unitName = "m/z";
cv_param.setValue("");
cv_param.toMzml(writer);
}
else if(unit == "MS:1000515")
{
//<cvParam cvRef="MS" accession="MS:1000515" value="" name="intensity array"
// unitAccession="MS:1000131" unitName="number of counts" unitCvRef="MS" />
cv_param.accession = unit;
cv_param.name = "intensity array";
cv_param.unitCvRef = "MS";
cv_param.unitAccession = "MS:1000131";
cv_param.unitName = "number of counts";
cv_param.setValue("");
cv_param.toMzml(writer);
}
else if(unit == "MS:1000595")
{
// <cvParam cvRef="MS" accession="MS:1000595" name="time array" value=""
// unitCvRef="UO" unitAccession="UO:0000031" unitName="minute"/>
cv_param.accession = unit;
cv_param.name = "time array";
cv_param.unitCvRef = "UO";
cv_param.unitAccession = "UO:0000031";
cv_param.unitName = "minute";
cv_param.setValue("");
cv_param.toMzml(writer);
}
else if(unit == "MS:1000786")
{
// <cvParam cvRef="MS" accession="MS:1000786" name="non-standard data
// array" value="ms level" unitCvRef="UO" unitAccession="UO:0000186"
// unitName="dimensionless unit"/>
//
cv_param.accession = unit;
cv_param.name = "non-standard data array";
cv_param.unitCvRef = "UO";
cv_param.unitAccession = "UO:0000186";
cv_param.unitName = "dimensionless unit";
cv_param.setValue("ms level");
cv_param.toMzml(writer);
}
else
{
throw pappso::PappsoException(
QObject::tr("unit accession %1 is not known in binaryDataArray").arg(unit));
}
// <cvParam cvRef="MS" accession="MS:1000523" value="" name="64-bit float" />
cv_param.unitCvRef.clear();
cv_param.unitAccession.clear();
cv_param.unitName.clear();
cv_param.setValue("");
if(isInt)
{
/*
id: MS:1000519
name: 32-bit integer
def: "Signed 32-bit little-endian integer." [PSI:MS]
is_a: MS:1000518 ! binary data type*/
if(bits == 32)
{
cv_param.accession = "MS:1000519";
cv_param.name = "32-bit integer";
cv_param.toMzml(writer);
}
else if(bits == 64)
{
/*
[Term]
id: MS:1000522
name: 64-bit integer
def: "Signed 64-bit little-endian integer." [PSI:MS]
is_a: MS:1000518 ! binary data type*/
cv_param.accession = "MS:1000522";
cv_param.name = "64-bit integer";
cv_param.toMzml(writer);
}
}
else
{
if(bits == 64)
{
cv_param.accession = "MS:1000523";
cv_param.name = "64-bit float";
cv_param.toMzml(writer);
}
else if(bits == 32)
{
/*
[Term]
id: MS:1000521
name: 32-bit float
def: "32-bit precision little-endian floating point conforming to IEEE-754." [PSI:MS]
is_a: MS:1000518 ! binary data type
*/
cv_param.accession = "MS:1000521";
cv_param.name = "32-bit float";
cv_param.toMzml(writer);
}
}
// <cvParam cvRef="MS" accession="MS:1000574" value="" name="zlib compression" />
/*
[Term]
id: MS:1000520
name: 16-bit float
def: "OBSOLETE Signed 16-bit float." [PSI:MS]
is_a: MS:1000518 ! binary data type
is_obsolete: true
[Term]
id: MS:1000523
name: 64-bit float
def: "64-bit precision little-endian floating point conforming to IEEE-754." [PSI:MS]
is_a: MS:1000518 ! binary data type
*/
if(compress == "zlib")
{
cv_param.accession = "MS:1000574";
cv_param.name = "zlib compression";
cv_param.toMzml(writer);
}
else if(compress == "none")
{ /*
[Term]
id: MS:1000576
name: no compression
def: "No Compression." [PSI:MS]
is_a: MS:1000572 ! binary data compression type
*/
cv_param.accession = "MS:1000576";
cv_param.name = "no compression";
cv_param.toMzml(writer);
}
// <binary>eJwl0W9oW1U
// writer.writeStartElement("binary");
writer.writeTextElement("binary", base64);
// </binary>
// writer.writeEndElement();
// </binaryDataArray>
writer.writeEndElement();
}
void
pappso::cbor::mzcbor::BinaryDataArray::decodeVector(std::size_t estimated_length,
std::vector<double> &double_list) const
{
qDebug();
int size_in_byte = 8;
if(bits == 32)
{
size_in_byte = 4;
}
qDebug();
// if(result.decodingStatus == QByteArray::Base64DecodingStatus::Ok)
// { // Allocate buffer for decompressed data
if(compress == "zlib")
{
qDebug();
std::vector<unsigned char> data_heap;
uLongf decompressedSize = estimated_length * size_in_byte; // Estimate size
data_heap.resize(decompressedSize);
// Decompress the data
int result_zlib = uncompress(
data_heap.data(), &decompressedSize, (Bytef *)byteArray.constData(), byteArray.size());
if(result_zlib != Z_OK)
{
throw pappso::PappsoException(QObject::tr("Decompression failed: %1").arg(result_zlib));
}
// Resize the vector to the actual decompressed size
data_heap.resize(decompressedSize);
double_list.resize(decompressedSize / size_in_byte);
// double *double_ptr = (double *)&decompressedData[0];
std::size_t j = 0;
for(std::size_t i = 0; i < data_heap.size(); i += size_in_byte)
{
if(bits == 32)
{
if(isInt)
{
double_list[j] = *(std::int32_t *)&data_heap[i];
}
else
{
double_list[j] = *(std::float_t *)&data_heap[i];
}
}
else
{
if(isInt)
{
double_list[j] = *(std::int64_t *)&data_heap[i];
}
else
{
double_list[j] = *(double *)&data_heap[i];
}
}
// double_ptr++;
j++;
}
}
else if(compress == "none")
{
qDebug() << size_in_byte << " " << byteArray.size();
double_list.resize(byteArray.size() / size_in_byte);
// double *double_ptr = (double *)&decompressedData[0];
std::size_t j = 0;
for(std::size_t i = 0; i < (std::size_t)byteArray.size(); i += size_in_byte)
{
qDebug() << " i=" << i;
if(bits == 32)
{
if(isInt)
{
double_list[j] = *(std::int32_t *)&byteArray.constData()[i];
}
else
{
double_list[j] = *(std::float_t *)&byteArray.constData()[i];
}
}
else
{
if(isInt)
{
double_list[j] = *(std::int64_t *)&byteArray.constData()[i];
}
else
{
qDebug();
double_list[j] = *(double *)&byteArray.constData()[i];
}
}
// double_ptr++;
j++;
}
}
qDebug();
// std::vector<double> v(decompressedData.cbegin(), decompressedData.cend());
// qDebug() << j << " " << double_list.size();
}
bool
pappso::cbor::mzcbor::BinaryDataArray::isIntensity() const
{
// <cvParam cvRef="MS" accession="MS:1000515" value="" name="intensity array"
// unitAccession="MS:1000131" unitName="number of counts" unitCvRef="MS" />
return unit == "MS:1000515";
}
bool
pappso::cbor::mzcbor::BinaryDataArray::isMz() const
{
// <cvParam cvRef="MS" accession="MS:1000514" value="" name="m/z array"
// unitAccession="MS:1000040" unitName="m/z" unitCvRef="MS" />
return unit == "MS:1000514";
}
QJsonObject
pappso::cbor::mzcbor::BinaryDataArray::toJsonObject(std::size_t estimated_length) const
{
QJsonObject binary_data;
binary_data.insert("unit", unit);
std::vector<double> double_list;
decodeVector(estimated_length, double_list);
QJsonArray double_array;
for(auto &value : double_list)
{
double_array.append(value);
}
binary_data.insert("array", double_array);
return binary_data;
}
binarydataarray.h
PSI BinaryDataArray object for mzML/mzCBOR.
pappso::PappsoException
Definition pappsoexception.h:41
pappso::cbor::CborStreamReader
simple override of the raw QCborStreamReader This adds convenient functions to put CBOR data into C++...
Definition cborstreamreader.h:46
pappso::cbor::CborStreamReader::decodeString
bool decodeString(QString &the_str)
decode the current cbor value as a string the point to the next value the current value is decoded as...
Definition cborstreamreader.cpp:48
pappso::cbor::CborStreamWriter
overrides QCborStreamWriter base class to provide convenient functions
Definition cborstreamwriter.h:45
cvparam.h
PSI cvParam object for mzML/mzCBOR.
pappsoexception.h
pappso::cbor::mzcbor::BinaryDataArray::fromCbor
void fromCbor(CborStreamReader &reader)
Definition binarydataarray.cpp:37
pappso::cbor::mzcbor::BinaryDataArray::isMz
bool isMz() const
Definition binarydataarray.cpp:578
pappso::cbor::mzcbor::BinaryDataArray::isInt
bool isInt
Definition binarydataarray.h:61
pappso::cbor::mzcbor::BinaryDataArray::fromMzml
void fromMzml(QXmlStreamReader &reader)
Definition binarydataarray.cpp:132
pappso::cbor::mzcbor::BinaryDataArray::toMzml
void toMzml(QXmlStreamWriter &writer)
Definition binarydataarray.cpp:290
pappso::cbor::mzcbor::BinaryDataArray::toCbor
void toCbor(CborStreamWriter &writer)
Definition binarydataarray.cpp:111
pappso::cbor::mzcbor::BinaryDataArray::isIntensity
bool isIntensity() const
Definition binarydataarray.cpp:569
pappso::cbor::mzcbor::BinaryDataArray::compress
QString compress
Definition binarydataarray.h:62
pappso::cbor::mzcbor::BinaryDataArray::bits
quint8 bits
Definition binarydataarray.h:60
pappso::cbor::mzcbor::BinaryDataArray::unit
QString unit
Definition binarydataarray.h:63
pappso::cbor::mzcbor::BinaryDataArray::decodeVector
void decodeVector(std::size_t estimated_length, std::vector< double > &double_list) const
Definition binarydataarray.cpp:459
pappso::cbor::mzcbor::BinaryDataArray::byteArray
QByteArray byteArray
Definition binarydataarray.h:65
pappso::cbor::mzcbor::BinaryDataArray::toJsonObject
QJsonObject toJsonObject(std::size_t estimated_length) const
write the structure to a JSON object needs to decode the binary array
Definition binarydataarray.cpp:587
pappso::cbor::mzcbor::CvParam
Definition cvparam.h:47
pappso::cbor::mzcbor::CvParam::cvRef
QString cvRef
Definition cvparam.h:73
pappso::cbor::mzcbor::CvParam::accession
QString accession
Definition cvparam.h:74
pappso::cbor::mzcbor::CvParam::unitName
QString unitName
Definition cvparam.h:80
pappso::cbor::mzcbor::CvParam::setValue
void setValue(const QString &value_str)
Definition cvparam.cpp:224
pappso::cbor::mzcbor::CvParam::unitCvRef
QString unitCvRef
Definition cvparam.h:81
pappso::cbor::mzcbor::CvParam::unitAccession
QString unitAccession
Definition cvparam.h:79
pappso::cbor::mzcbor::CvParam::toMzml
void toMzml(QXmlStreamWriter &writer)
Definition cvparam.cpp:232
pappso::cbor::mzcbor::CvParam::name
QString name
Definition cvparam.h:78