Mercurial > clickerconvert
view src/xlsx/xlsxsharedstrings.cpp @ 43:f9a0b2b6832e
Sanitize input and unify Lineendings
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 12 May 2016 17:35:49 +0200 |
parents | 93d3106bb9a4 |
children |
line wrap: on
line source
/**************************************************************************** ** Copyright (c) 2013-2014 Debao Zhang <hello@debao.me> ** All right reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining ** a copy of this software and associated documentation files (the ** "Software"), to deal in the Software without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Software, and to ** permit persons to whom the Software is furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be ** included in all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND ** NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE ** LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION ** OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION ** WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** ****************************************************************************/ #include "xlsxrichstring.h" #include "xlsxsharedstrings_p.h" #include "xlsxutility_p.h" #include "xlsxformat_p.h" #include "xlsxcolor_p.h" #include <QXmlStreamWriter> #include <QXmlStreamReader> #include <QDir> #include <QFile> #include <QDebug> #include <QBuffer> namespace QXlsx { /* * Note that, when we open an existing .xlsx file (broken file?), * duplicated string items may exist in the shared string table. * * In such case, the size of stringList will larger than stringTable. * Duplicated items can be removed once we loaded all the worksheets. */ SharedStrings::SharedStrings(CreateFlag flag) :AbstractOOXmlFile(flag) { m_stringCount = 0; } int SharedStrings::count() const { return m_stringCount; } bool SharedStrings::isEmpty() const { return m_stringList.isEmpty(); } int SharedStrings::addSharedString(const QString &string) { return addSharedString(RichString(string)); } int SharedStrings::addSharedString(const RichString &string) { m_stringCount += 1; if (m_stringTable.contains(string)) { XlsxSharedStringInfo &item = m_stringTable[string]; item.count += 1; return item.index; } int index = m_stringList.size(); m_stringTable[string] = XlsxSharedStringInfo(index); m_stringList.append(string); return index; } void SharedStrings::incRefByStringIndex(int idx) { if (idx <0 || idx >= m_stringList.size()) { qDebug("SharedStrings: invlid index"); return; } addSharedString(m_stringList[idx]); } /* * Broken, don't use. */ void SharedStrings::removeSharedString(const QString &string) { removeSharedString(RichString(string)); } /* * Broken, don't use. */ void SharedStrings::removeSharedString(const RichString &string) { if (!m_stringTable.contains(string)) return; m_stringCount -= 1; XlsxSharedStringInfo &item = m_stringTable[string]; item.count -= 1; if (item.count <= 0) { for (int i=item.index+1; i<m_stringList.size(); ++i) m_stringTable[m_stringList[i]].index -= 1; m_stringList.removeAt(item.index); m_stringTable.remove(string); } } int SharedStrings::getSharedStringIndex(const QString &string) const { return getSharedStringIndex(RichString(string)); } int SharedStrings::getSharedStringIndex(const RichString &string) const { if (m_stringTable.contains(string)) return m_stringTable[string].index; return -1; } RichString SharedStrings::getSharedString(int index) const { if (index < m_stringList.count() && index >= 0) return m_stringList[index]; return RichString(); } QList<RichString> SharedStrings::getSharedStrings() const { return m_stringList; } void SharedStrings::writeRichStringPart_rPr(QXmlStreamWriter &writer, const Format &format) const { if (!format.hasFontData()) return; if (format.fontBold()) writer.writeEmptyElement(QStringLiteral("b")); if (format.fontItalic()) writer.writeEmptyElement(QStringLiteral("i")); if (format.fontStrikeOut()) writer.writeEmptyElement(QStringLiteral("strike")); if (format.fontOutline()) writer.writeEmptyElement(QStringLiteral("outline")); if (format.boolProperty(FormatPrivate::P_Font_Shadow)) writer.writeEmptyElement(QStringLiteral("shadow")); if (format.hasProperty(FormatPrivate::P_Font_Underline)) { Format::FontUnderline u = format.fontUnderline(); if (u != Format::FontUnderlineNone) { writer.writeEmptyElement(QStringLiteral("u")); if (u== Format::FontUnderlineDouble) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("double")); else if (u == Format::FontUnderlineSingleAccounting) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("singleAccounting")); else if (u == Format::FontUnderlineDoubleAccounting) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("doubleAccounting")); } } if (format.hasProperty(FormatPrivate::P_Font_Script)) { Format::FontScript s = format.fontScript(); if (s != Format::FontScriptNormal) { writer.writeEmptyElement(QStringLiteral("vertAlign")); if (s == Format::FontScriptSuper) writer.writeAttribute(QStringLiteral("val"), QStringLiteral("superscript")); else writer.writeAttribute(QStringLiteral("val"), QStringLiteral("subscript")); } } if (format.hasProperty(FormatPrivate::P_Font_Size)) { writer.writeEmptyElement(QStringLiteral("sz")); writer.writeAttribute(QStringLiteral("val"), QString::number(format.fontSize())); } if (format.hasProperty(FormatPrivate::P_Font_Color)) { XlsxColor color = format.property(FormatPrivate::P_Font_Color).value<XlsxColor>(); color.saveToXml(writer); } if (!format.fontName().isEmpty()) { writer.writeEmptyElement(QStringLiteral("rFont")); writer.writeAttribute(QStringLiteral("val"), format.fontName()); } if (format.hasProperty(FormatPrivate::P_Font_Family)) { writer.writeEmptyElement(QStringLiteral("family")); writer.writeAttribute(QStringLiteral("val"), QString::number(format.intProperty(FormatPrivate::P_Font_Family))); } if (format.hasProperty(FormatPrivate::P_Font_Scheme)) { writer.writeEmptyElement(QStringLiteral("scheme")); writer.writeAttribute(QStringLiteral("val"), format.stringProperty(FormatPrivate::P_Font_Scheme)); } } void SharedStrings::saveToXmlFile(QIODevice *device) const { QXmlStreamWriter writer(device); if (m_stringList.size() != m_stringTable.size()) { //Duplicated string items exist in m_stringList //Clean up can not be done here, as the indices //have been used when we save the worksheets part. } writer.writeStartDocument(QStringLiteral("1.0"), true); writer.writeStartElement(QStringLiteral("sst")); writer.writeAttribute(QStringLiteral("xmlns"), QStringLiteral("http://schemas.openxmlformats.org/spreadsheetml/2006/main")); writer.writeAttribute(QStringLiteral("count"), QString::number(m_stringCount)); writer.writeAttribute(QStringLiteral("uniqueCount"), QString::number(m_stringList.size())); foreach (RichString string, m_stringList) { writer.writeStartElement(QStringLiteral("si")); if (string.isRichString()) { //Rich text string for (int i=0; i<string.fragmentCount(); ++i) { writer.writeStartElement(QStringLiteral("r")); if (string.fragmentFormat(i).hasFontData()) { writer.writeStartElement(QStringLiteral("rPr")); writeRichStringPart_rPr(writer, string.fragmentFormat(i)); writer.writeEndElement();// rPr } writer.writeStartElement(QStringLiteral("t")); if (isSpaceReserveNeeded(string.fragmentText(i))) writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve")); writer.writeCharacters(string.fragmentText(i)); writer.writeEndElement();// t writer.writeEndElement(); //r } } else { writer.writeStartElement(QStringLiteral("t")); QString pString = string.toPlainString(); if (isSpaceReserveNeeded(pString)) writer.writeAttribute(QStringLiteral("xml:space"), QStringLiteral("preserve")); writer.writeCharacters(pString); writer.writeEndElement();//t } writer.writeEndElement();//si } writer.writeEndElement(); //sst writer.writeEndDocument(); } void SharedStrings::readString(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("si")); RichString richString; while (!reader.atEnd() && !(reader.name() == QLatin1String("si") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("r")) readRichStringPart(reader, richString); else if (reader.name() == QLatin1String("t")) readPlainStringPart(reader, richString); } } int idx = m_stringList.size(); m_stringTable[richString] = XlsxSharedStringInfo(idx, 0); m_stringList.append(richString); } void SharedStrings::readRichStringPart(QXmlStreamReader &reader, RichString &richString) { Q_ASSERT(reader.name() == QLatin1String("r")); QString text; Format format; while (!reader.atEnd() && !(reader.name() == QLatin1String("r") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("rPr")) { format = readRichStringPart_rPr(reader); } else if (reader.name() == QLatin1String("t")) { text = reader.readElementText(); } } } richString.addFragment(text, format); } void SharedStrings::readPlainStringPart(QXmlStreamReader &reader, RichString &richString) { Q_ASSERT(reader.name() == QLatin1String("t")); //QXmlStreamAttributes attributes = reader.attributes(); QString text = reader.readElementText(); richString.addFragment(text, Format()); } Format SharedStrings::readRichStringPart_rPr(QXmlStreamReader &reader) { Q_ASSERT(reader.name() == QLatin1String("rPr")); Format format; while (!reader.atEnd() && !(reader.name() == QLatin1String("rPr") && reader.tokenType() == QXmlStreamReader::EndElement)) { reader.readNextStartElement(); if (reader.tokenType() == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = reader.attributes(); if (reader.name() == QLatin1String("rFont")) { format.setFontName(attributes.value(QLatin1String("val")).toString()); } else if (reader.name() == QLatin1String("charset")) { format.setProperty(FormatPrivate::P_Font_Charset, attributes.value(QLatin1String("val")).toString().toInt()); } else if (reader.name() == QLatin1String("family")) { format.setProperty(FormatPrivate::P_Font_Family, attributes.value(QLatin1String("val")).toString().toInt()); } else if (reader.name() == QLatin1String("b")) { format.setFontBold(true); } else if (reader.name() == QLatin1String("i")) { format.setFontItalic(true); } else if (reader.name() == QLatin1String("strike")) { format.setFontStrikeOut(true); } else if (reader.name() == QLatin1String("outline")) { format.setFontOutline(true); } else if (reader.name() == QLatin1String("shadow")) { format.setProperty(FormatPrivate::P_Font_Shadow, true); } else if (reader.name() == QLatin1String("condense")) { format.setProperty(FormatPrivate::P_Font_Condense, attributes.value(QLatin1String("val")).toString().toInt()); } else if (reader.name() == QLatin1String("extend")) { format.setProperty(FormatPrivate::P_Font_Extend, attributes.value(QLatin1String("val")).toString().toInt()); } else if (reader.name() == QLatin1String("color")) { XlsxColor color; color.loadFromXml(reader); format.setProperty(FormatPrivate::P_Font_Color, color); } else if (reader.name() == QLatin1String("sz")) { format.setFontSize(attributes.value(QLatin1String("val")).toString().toInt()); } else if (reader.name() == QLatin1String("u")) { QString value = attributes.value(QLatin1String("val")).toString(); if (value == QLatin1String("double")) format.setFontUnderline(Format::FontUnderlineDouble); else if (value == QLatin1String("doubleAccounting")) format.setFontUnderline(Format::FontUnderlineDoubleAccounting); else if (value == QLatin1String("singleAccounting")) format.setFontUnderline(Format::FontUnderlineSingleAccounting); else format.setFontUnderline(Format::FontUnderlineSingle); } else if (reader.name() == QLatin1String("vertAlign")) { QString value = attributes.value(QLatin1String("val")).toString(); if (value == QLatin1String("superscript")) format.setFontScript(Format::FontScriptSuper); else if (value == QLatin1String("subscript")) format.setFontScript(Format::FontScriptSub); } else if (reader.name() == QLatin1String("scheme")) { format.setProperty(FormatPrivate::P_Font_Scheme, attributes.value(QLatin1String("val")).toString()); } } } return format; } bool SharedStrings::loadFromXmlFile(QIODevice *device) { QXmlStreamReader reader(device); int count = 0; bool hasUniqueCountAttr=true; while (!reader.atEnd()) { QXmlStreamReader::TokenType token = reader.readNext(); if (token == QXmlStreamReader::StartElement) { if (reader.name() == QLatin1String("sst")) { QXmlStreamAttributes attributes = reader.attributes(); if ((hasUniqueCountAttr = attributes.hasAttribute(QLatin1String("uniqueCount")))) count = attributes.value(QLatin1String("uniqueCount")).toString().toInt(); } else if (reader.name() == QLatin1String("si")) { readString(reader); } } } if (hasUniqueCountAttr && m_stringList.size() != count) { qDebug("Error: Shared string count"); return false; } if (m_stringList.size() != m_stringTable.size()) { //qDebug("Warning: Duplicated items exist in shared string table."); //Nothing we can do here, as indices of the strings will be used when loading sheets. } return true; } } //namespace