libxml2: center text in comment section - libxml2

I try to center the text horizontally and vertically in xml doc, comment section (necessary to automated this when text are translated in po files).
For this I mixed glib and libxml2 api:
static const xmlChar *text[] = {
N_("Configuration file"),
N_("This file was automatically generated."),
N_("Please MAKE SURE TO BACKUP THIS FILE before making changes."),
NULL
};
xmlChar *centered_text (const xmlChar **array)
{
GString *string;
guint i;
string = g_string_new ("\n");
for (i = 0; array[i]; i++)
{
gint width;
width = (80 - strlen (array[i])) / 2 + strlen (array[i]);
g_string_append_printf (string, "%*s\n", width, array[i]);
}
return g_string_free (string, FALSE);
}
.......................
xmlDocPtr doc;
xmlChar *content;
xmlNodePtr comment;
doc = xmlNewDoc ((const xmlChar *) "1.0");
content = centered_text (text);
comment = xmlNewDocComment (doc, (const xmlChar *) content);
xmlFree (content);
xmlAddChild ((xmlNodePtr) doc, comment);
And output file look like this:
<?xml version="1.0" encoding="UTF-8"?>
<!--
Configuration file
This file was automatically generated.
Please MAKE SURE TO BACKUP THIS FILE before making changes.
-->
Here is for example a italian translation without alignment:
File di configurazione
Questo file รจ stato generato automaticamente.
Assicurati di file di questo backup prima di apportare modifiche.
There is a way to do this using only libxml2 ?

You can append text content to comment nodes with xmlNodeAddContent and xmlNodeAddContentLen. libxml2 also supports a couple of functions for string manipulation, but there's no equivalent to g_string_append_printf. I'd go with the following approach:
xmlDocPtr doc;
xmlNodePtr comment;
int i;
doc = xmlNewDoc((const xmlChar *)"1.0");
comment = xmlNewDocComment(doc, (const xmlChar *)"");
for (i = 0; array[i]; i++) {
/* 40 space characters. */
static const char space[] = " ";
int len = strlen(array[i]);
if (len < 80)
xmlNodeAddContentLen(comment, (const xmlChar *)space, (80 - len) / 2);
xmlNodeAddContentLen(comment, (const xmlChar *)array[i], len);
xmlNodeAddContentLen(comment, (const xmlChar *)"\n", 1);
}

Related

memmove implementation throws segmentation fault while copying a character array

Hi I tried to write my own version of memmove and I find the following code resulting in a segmentation fault. It would be great if someone could help me figure out why this behavior would occur!
However, when I use something like:
char source[20] = "Hello, this is Piranava", the code works fine!
void *memmoveLocal(void *dest, const void *src, unsigned int n)
{
char *destL = dest;
const char *srcL = src;
int i = 0;
if(dest == NULL || src == NULL)
{
return NULL;
}
else
{
// if dest comes before source, even if there's an overlap, we should move forward
// because if there's an overlap (when dest < src) and we move backward, we'd overwrite the overlapping bytes in src
if(destL < srcL)
{
printf("Forward\n");
while(i < n)
{
destL[i] = srcL[i];
i++;
}
}
else // in all other cases (even if there's overlap or no overlap, we can move backward)
{
printf("Backward\n");
i = n - 1;
while(i >= 0)
{
destL[i] = srcL[i];
i--;
}
}
}
return dest;
}
void main()
{
char *source = "Hello, this is ABC";
char *destination = malloc(strlen(source)+1);
memmoveLocal(source+5, source, 5);
printf("Source: %s \nDestination: %s, size: %d\n", source, destination, strlen(destination));
}
However, if I replace
char *source = "Hello, this is ABC";
with
char source[20] = "Hello, this is ABC";
, it works fine!
memmoveLocal(source+5, source, 5);
You are trying to overwrite a string literal, which is not writable.
Did you intend to memmoveLocal(destination, source+5, 5) instead?
char source[20] = "Hello, this is ABC";
That turns source from a string literal into a char[] array initialized with a string literal. The array is writable, so your program no longer crashes.

QT String to char * adds extra characters

I have a qTextEdit that I grab the text from (QString) and convert to a char* with this code:
QString msgQText = ui->textMsg->toPlainText();
size_t textSize = (size_t)msgQText.size();
if (textSize > 139) {
textSize = 139;
}
unsigned char * msgText = (unsigned char *)malloc(textSize);
memcpy(msgText, msgQText.toLocal8Bit().data(), textSize);
msgText[textSize] = '\0';
if (textSize > 0) {
Msg * newTextMsg = new Msg;
newTextMsg->type = 1; // text message type
newTextMsg->bitrate = 0;
newTextMsg->samplerate = 0;
newTextMsg->bufSize = (int)textSize;
newTextMsg->len = 0;
newTextMsg->buf = (char *)malloc(textSize);
memcpy((char *)newTextMsg->buf, (char *)msgText, textSize);
lPushToEnd(sendMsgList, newTextMsg, sizeof(Msg));
ui->sendRecList->addItem((char *)newTextMsg->buf);
ui->textMsg->clear();
}
I put the text into a qListBox, but it shows up like
However, the character array, if I print it out, does not have the extra characters.
I have tried checking the "compile using UTF-8" option, but it doesn't make a difference.
Also, I send the text using RS232, and the receiver side also displays the extra characters.
The receiver code is here:
m_serial->waitForReadyRead(200);
const QByteArray data = m_serial->readAll();
if (data.size() > 0) {
qDebug() << "New serial data: " << data;
QString str = QString(data);
if (str.contains("0x6F8C32E90A")) {
qDebug() << "TEST SUCCESSFUL!";
}
return data.data();
} else {
return NULL;
}
There is a difference between the size of a QString and the size of the QByteArray returned by toLocal8Bit(). A QString contains unicode text stored as UTF-16, while a QByteArray is "just" a char[].
A QByteArray is null-terminated, so you do not need to add it manually.
As #GM pointed out: msgText[textSize] = '\0'; is undefined behavior. You are writing to the textSize + 1 position of the msgText array.
This position may be owned by something else and may be overwritten, so you end up with a non null terminated string.
This should work:
QByteArray bytes = msgQText.toLocal8Bit();
size_t textSize = (size_t)bytes.size() + 1; // Add 1 for the final '\0'
unsigned char * msgText = (unsigned char *) malloc(textSize);
memcpy(msgText, bytes.constData(), textSize);
Additional tips:
Prefer using const functions on Qt types that are copy-on-write, e.g. use QBytearray::constData() instead of QByteArray::data(). The non-const functions can cause a deep-copy of the object.
Do not use malloc() and other C-style functions if possible. Here you could do:
unsigned char * msgText = new unsigned char[textSize]; and later delete[] msgText;.
Prefer using C++ casts (static_cast, reinterpret_cast, etc.) instead of C-style casts.
You are making 2 copies of the text (2 calls to memcpy), given your code only 1 seem to be enough.

Not able to reconstruct RGB565 image from raw data using QImage

I am trying to reconstruct an image from a file which is in Intel hex 386 format. After parsing the file all the data I am copying to a QByteArray and same array is used to create a QImage Object. But whatever image is which I got after reconstructing is not perfect. I am getting blue color instead of black, edges are not clear etc. The text file which I am parsing is a ram memory dump from STM32F4 controller (arm).The image is stored in RGB565 format.
Code to create the image:
{
QString strFilename;
Hex386Parser oFileParser;
strFilename = QFileDialog::getOpenFileName(this,"Select a file", QDir::homePath());
oFileParser.parseFile(strFilename, oByteArray);
QImage image(320, 240, QImage::Format_RGB16);
for (int y = 0; y < image.height(); y++)
{
memcpy(image.scanLine(y), oByteArray.constData() + y * image.bytesPerLine(),
image.bytesPerLine());
}
qDebug() <<"Size of the byte array is " <<oByteArray.size();
QLabel *label = new QLabel();
label->setPixmap(QPixmap::fromImage(image));
label->show();
}
Code to used to parse the file:
#define QT_NO_CAST_TO_ASCII
void Hex386Parser::parseFile(QString strFilename,QByteArray& ref_ByteArray)
{
QFile oFile(strFilename);
std::stringstream sstr;
QString strLength;
int unLength = 0, unAddress = 0,unDescriptor =0xFFFF,nIndex =0,nlineno=0;
if (oFile.open((QIODevice::ReadOnly | QIODevice::Text)))
{
QTextStream in(&oFile);
while (!in.atEnd())
{
QString line = in.readLine();
nIndex = 0;
nlineno++;
//unsigned char *pCharFrame = (unsigned char *)line.toStdString().c_str();
if (':' != line.at(nIndex))
{
// file corrupted
return;
}
nIndex++;
{
strLength = line.mid(nIndex, 2);
sstr << strLength.toStdString();
sstr << std::hex;
sstr >> unLength; // get length of the record
strLength.clear();
sstr.clear();
}
nIndex += 2;
unAddress = line.mid(nIndex,4).toInt(); // get address bytes
nIndex +=4;
unDescriptor = line.mid(nIndex, 2).toInt(); // get data descriptor
nIndex += 2;
switch(unDescriptor)
{
case data_record:
ref_ByteArray.append((line.mid(nIndex, unLength )));
// add data to bytearray
break;
case end_of_file_record:
break;
case extended_segment_address_record:
break;
case extended_linear_address_record:
break;
case start_linear_address_record:
break;
}
}
oFile.close();
}
}
What am I doing wrong??
The line contains hex string data representations where each byte is coded as two characters.
You want binary bytes. So, 2 * unLength symbols should be read from line. Then, that data string should converted to binary, for example:
{
case data_record:
QByteArray hex = line.mid(nIndex, 2 * unLength ).toLatin1();
QByteArray binary = QByteArray::fromHex(hex);
ref_ByteArray.append(binary);
...
}

Add additional xsd schemas with libXml2

I have a xml and schema which I want to validate. I don't want schema to be stored in file, but in database location. I use xmlSchemaNewMemParserCtxt to parse the schema. The problem is that this schema references another schema for basic types: <xs:include schemaLocation="CommonTypes.xsd"/>, which libXml2 searches in the current working directory. Is there any way to supply these additional schemas in memory buffer?
xmlRegisterInputCallbacks is what you're probably looking for.
The advantage, they let you construct some kind of a virtual I/O layer. The disadvantage, inputcallbacks are set globally (there is however xmlPopInputCallbacks and xmlCleanupInputCallbacks).
The code below (built upon code from http://knol2share.blogspot.be) demonstrates the use of xmlRegisterInputCallbacks.
All xml and xsd files are loaded from the file system, except when the URI contains "DataTypes.xsd" the schema is fetched from a string. (since schemaLocation is only a hint one could for example prefix schema's
"test.xsd": the main xml schema (please ignore the reference to peacelane.org, namespaces are from a hobby project, just occurred to me now www.peacelane.org might exist, apparently it does...)
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
xmlns:dt="http://peacelane.org/ApplianceType/config/45/DataTypes"
targetNamespace="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
elementFormDefault="qualified">
<import namespace="http://peacelane.org/ApplianceType/config/45/DataTypes" schemaLocation="DataTypes.xsd" />
<complexType name="ConfigType">
<sequence>
<element name="housecode" type="dt:char" />
</sequence>
</complexType>
<element name="Config" type="tns:ConfigType"/>
</schema>
"test.xml": a test xml to validate
<?xml version="1.0"?>
<Config xmlns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC">
<housecode>A</housecode>
</Config>
"main.c": the actual code (update the paths for "XMLFileName" and "XSDFileName")
#define LIBXML_SCHEMAS_ENABLED
#include <libxml/xmlschemastypes.h>
#include <stdio.h>
static const char *databaseSchema =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
" <schema elementFormDefault=\"qualified\" xmlns:tns=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" targetNamespace=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" xmlns=\"http://www.w3.org/2001/XMLSchema\">"
" <simpleType name=\"char\">"
" <restriction base=\"string\">"
" <length value=\"1\" />"
" </restriction>"
" </simpleType>"
" </schema>";
//-----------------------------------------------------------------------------
//-- SQL Callbacks (~ simulated db actions)
//-----------------------------------------------------------------------------
static void* sqlOpen(const char * URI) {
return ((void *) databaseSchema );
}
static int sqlClose(void * context) {
return (0);
}
static int sqlRead(void * context, char * buffer, int len) {
const char* result= (const char *) context;
int rlen = strlen(result);
memcpy(buffer, result, rlen);
return rlen +1;
}
static int sqlMatch(const char * URI) {
if ((URI != NULL )&& (strstr(URI, "DataTypes.xsd") != NULL) )return 1;
return 0;
}
//-----------------------------------------------------------------------------
//-- File callbacks
//-----------------------------------------------------------------------------
static void* fileOpen(const char * URI) {
if (URI == NULL )
return (NULL );
FILE* fh = fopen(URI, "rt");
return ((void *) fh);
}
static int fileClose(void * context) {
FILE* fh = (FILE*) context;
if (fh != NULL )
fclose(fh);
return (0);
}
static int fileRead(void * context, char * buffer, int len) {
FILE* fh = (FILE*) context;
fseek(fh, 0L, SEEK_END);
long flen = ftell(fh);
rewind(fh);
if (buffer != NULL )
fread(buffer, flen, 1, fh);
return flen + 1;
}
static int fileMatch(const char * URI) {
if ((URI != NULL ))
if (strstr(URI, "DataTypes.xsd") == NULL ) {
return (1);
}
return (0);
}
//-----------------------------------------------------------------------------
//-- Main
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
xmlDocPtr doc;
xmlSchemaPtr schema = NULL;
xmlSchemaParserCtxtPtr ctxt;
char *XMLFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xml";
char *XSDFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xsd";
xmlLineNumbersDefault(1);
if (xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose)
< 0) {
fprintf(stderr, "failed to register File handler\n");
exit(1);
}
if (xmlRegisterInputCallbacks(sqlMatch, sqlOpen, sqlRead, sqlClose) < 0) {
fprintf(stderr, "failed to register SQL handler\n");
exit(1);
}
ctxt = xmlSchemaNewParserCtxt(XSDFileName);
xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
schema = xmlSchemaParse(ctxt);
xmlSchemaFreeParserCtxt(ctxt);
xmlSchemaDump(stdout, schema);
doc = xmlReadFile(XMLFileName, NULL, 0);
if (doc == NULL ) {
fprintf(stderr, "Could not parse %s\n", XMLFileName);
} else {
xmlSchemaValidCtxtPtr ctxt;
int ret;
ctxt = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
ret = xmlSchemaValidateDoc(ctxt, doc);
if (ret == 0) {
printf("%s validates\n", XMLFileName);
} else if (ret > 0) {
printf("%s fails to validate\n", XMLFileName);
} else {
printf("%s validation generated an internal error\n", XMLFileName);
}
xmlSchemaFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
}
if (schema != NULL )
xmlSchemaFree(schema);
xmlSchemaCleanupTypes();
xmlCleanupParser();
xmlMemoryDump();
return (0);
}
Notice that, for brevity, the above code doesnt' perform any checks wether (file, memory,...) operations succeeded.
This is a better example how to do it: io1.c
http://www.xmlsoft.org/examples/
It saves a lot of time when you can find what is good way to return value from Read function.

Get filename from QFile?

eg:
QFile f("/home/umanga/Desktop/image.jpg");
How I get only the filename - "image.jpg"?
Use a QFileInfo to strip out the path (if any):
QFileInfo fileInfo(f.fileName());
QString filename(fileInfo.fileName());
One approach, not necessarily the best: from a QFile, you can get the file specification with QFile::fileName():
QFile f("/home/umanga/Desktop/image.jpg");
QString str = f.fileName();
then you can just use the string features like QString::split:
QStringList parts = str.split("/");
QString lastBit = parts.at(parts.size()-1);
just in addition: to seperate filename and file path having QFile f
QString path = f.fileName();
QString file = path.section("/",-1,-1);
QString dir = path.section("/",0,-2);
you don't need to create an additional fileInfo.
I use this:
bool utes::pathsplit(QString source,QString *path,QString *filename)
{
QString fn;
int index;
if (source == "") return(false);
fn = source.section("/", -1, -1);
if (fn == "") return(false);
index = source.indexOf(fn);
if (index == -1) return(false);
*path = source.mid(0,index);
*filename = fn;
return(true);
}

Resources