[libwps] 01/01: New upstream version 0.4.6
Rene Engelhard
rene at moszumanska.debian.org
Mon Jun 5 10:56:24 UTC 2017
This is an automated email from the git hooks/post-receive script.
rene pushed a commit to branch upstream
in repository libwps.
commit 3de912f5708b96a49f829c12af78cc85c03233ed
Author: Rene Engelhard <rene at rene-engelhard.de>
Date: Mon Jun 5 12:54:11 2017 +0200
New upstream version 0.4.6
---
ChangeLog | 75 ++++++++++++
NEWS | 4 +
configure | 26 ++---
configure.ac | 2 +-
inc/libwps/WPSDocument.h | 2 +-
src/lib/Lotus.cpp | 256 +++++++++++++++++++++++++++++++++++++---
src/lib/Lotus.h | 9 +-
src/lib/LotusGraph.cpp | 16 +--
src/lib/LotusSpreadsheet.cpp | 257 +++++++++++++++++++++++++++--------------
src/lib/LotusSpreadsheet.h | 2 +-
src/lib/LotusStyleManager.cpp | 32 ++++-
src/lib/QuattroSpreadsheet.cpp | 45 +++++---
src/lib/WKS4.cpp | 141 ++++++++++++++++++++--
src/lib/WKS4.h | 10 +-
src/lib/WKS4Spreadsheet.cpp | 50 +++++---
src/lib/WKS4Spreadsheet.h | 2 +
src/lib/WKSContentListener.cpp | 29 ++---
src/lib/WKSContentListener.h | 9 +-
src/lib/WKSParser.h | 4 +
src/lib/WPSCell.cpp | 30 ++++-
src/lib/WPSCell.h | 17 ++-
src/lib/WPSDocument.cpp | 24 +++-
src/lib/WPSHeader.cpp | 2 +-
src/lib/WPSHeader.h | 12 ++
src/lib/WPSTable.cpp | 59 ++++++++++
src/lib/WPSTable.h | 117 +++++++++++++++++++
src/lib/libwps_internal.cpp | 58 ++++++++++
src/lib/libwps_internal.h | 15 +++
28 files changed, 1101 insertions(+), 204 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index d80a5d9..1596d1c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,78 @@
+2017-03-04 osnola <alonso at loria.fr> [1d29e6f12d6928b2a39df41db5022c0f4ecdf4bb]
+
+tupdate some README's files...
+
+
+2017-03-03 osnola <alonso at loria.fr> [71b1309d0961d7d06b5064061a6e293e52663f2e]
+
+tcorrect some cppcheck and coverity warnings, ...
+
+
+2017-03-03 osnola <alonso at loria.fr> [edbf8d4b97d3b837fe850b25f0789919e49a2eb5]
+
+t Lotus .wk3,.wk4,.123: try also to retrieve password with length 13 or 14, small correction.
+
+
+2017-03-03 osnola <alonso at loria.fr> [9a2fc4978f882d09b687ec28520899a86fa35c81]
+
+tLotus .wk3,.wk4,.123: try also to retrieve password with length 13 or 14...
+
+
+2017-03-03 osnola <alonso at loria.fr> [6bd5cb55bf9dfccf331b8cb3e2558dc55244d492]
+
+tCorrect some compilers' warnings...
+
+
+2017-03-02 osnola <alonso at loria.fr> [7fec47b58e0847b613994e97815cef2949de6ba2]
+
+tLotus .wk3,.wk4,.123: add a function to retrieve small passwords (ie. with less than 13 characters), called when a bad password was given by the user...
+
+
+2017-03-02 osnola <alonso at loria.fr> [54bef8967115ce11740320e93a52423c2a1f8fb8]
+
+tLotus .123(SmartSuite 98): add support for password...
+
+
+2017-03-02 osnola <alonso at loria.fr> [5b56551409c4be08e338c6da72df064b3585d3e2]
+
+tLotus .123(SmartSuite 97): add support for password...
+
+
+2017-03-02 osnola <alonso at loria.fr> [efd8af05edebb43f6eb4fc8897961004c5cbb5ba]
+
+tLotus .wk[124]: add support for password, ...
+
+
+2017-03-01 osnola <alonso at loria.fr> [e94f72e01f3b5daead887352fc0fa92a7e25359f]
+
+tLotus .wk3: add support for password, ...
+
+
+2017-02-23 osnola <alonso at loria.fr> [402d40740b165efa05d227ff3dc5a96e3953c643]
+
+tLotus SmartSuite 9[6-8]: try to find more dupplicated cell, WPSCell.cpp: force cell's padding to 0pt.
+
+
+2017-02-23 osnola <alonso at loria.fr> [44eef88b2230ca42c24fc5365727f6012f97080d]
+
+tLotus SmartSuite 9[6-8]: try to retrieve some "merged" cells...
+
+
+2017-02-23 osnola <alonso at loria.fr> [d85a63302997a461bff9979d32415c08968a052d]
+
+tLotus SmartSuite 9[6-8]: better retrieving of column's width(and row's height).
+
+
+2017-02-22 osnola <alonso at loria.fr> [0a32c559959a751c69755998d9255c0e5d2960b7]
+
+tLotus SmartSuite 9[6-8]:improve the font's name, the cell's wrapping, the row's height retrieving...
+
+
+2017-01-09 osnola <alonso at loria.fr> [b9e9ceeffa6798044bbbfb39b5cb21fe2a592523]
+
+tconfigure.ac: update minor version...
+
+
2017-01-05 osnola <alonso at loria.fr> [d5ebb0c062cfb3d7b200565f22ec3945b0e9b91f]
tUpdate the README files...
diff --git a/NEWS b/NEWS
index 9155cc7..2966df0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+0.4.5 -> 0.4.6
+- Lotus 123: add support to read SmartSuite 98's files,
+- Lotus: allow to convert file with a password.
+
0.4.4 -> 0.4.5
- Lotus 123: add support to read SmartSuite 97's files,
- implement LICS conversion correctly.
diff --git a/configure b/configure
index 49f450e..f4c9dbe 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libwps 0.4.5.
+# Generated by GNU Autoconf 2.69 for libwps 0.4.6.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='libwps'
PACKAGE_TARNAME='libwps'
-PACKAGE_VERSION='0.4.5'
-PACKAGE_STRING='libwps 0.4.5'
+PACKAGE_VERSION='0.4.6'
+PACKAGE_STRING='libwps 0.4.6'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1379,7 +1379,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures libwps 0.4.5 to adapt to many kinds of systems.
+\`configure' configures libwps 0.4.6 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1449,7 +1449,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libwps 0.4.5:";;
+ short | recursive ) echo "Configuration of libwps 0.4.6:";;
esac
cat <<\_ACEOF
@@ -1592,7 +1592,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libwps configure 0.4.5
+libwps configure 0.4.6
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1991,7 +1991,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by libwps $as_me 0.4.5, which was
+It was created by libwps $as_me 0.4.6, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2857,7 +2857,7 @@ fi
# Define the identity of the package.
PACKAGE='libwps'
- VERSION='0.4.5'
+ VERSION='0.4.6'
cat >>confdefs.h <<_ACEOF
@@ -17156,9 +17156,9 @@ WPS_MAJOR_VERSION=0
WPS_MINOR_VERSION=4
-WPS_MICRO_VERSION=5
+WPS_MICRO_VERSION=6
-WPS_VERSION=0.4.5
+WPS_VERSION=0.4.6
WPS_OBJDIR=$objdir
@@ -17167,7 +17167,7 @@ LT_CURRENT=`expr 100 '*' 0 + 4`
# For 1.0.0 comment the first line and uncomment the second
LT_AGE=0
-LT_REVISION=5
+LT_REVISION=6
@@ -18742,7 +18742,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by libwps $as_me 0.4.5, which was
+This file was extended by libwps $as_me 0.4.6, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -18808,7 +18808,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-libwps config.status 0.4.5
+libwps config.status 0.4.6
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index 4d6a052..b2a2a80 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@ AC_PREREQ([2.65])
# ====================
m4_define([libwps_version_major],[0])
m4_define([libwps_version_minor],[4])
-m4_define([libwps_version_micro],[5])
+m4_define([libwps_version_micro],[6])
m4_define([libwps_version],[libwps_version_major.libwps_version_minor.libwps_version_micro])
# =============
diff --git a/inc/libwps/WPSDocument.h b/inc/libwps/WPSDocument.h
index bf681db..c8fee70 100644
--- a/inc/libwps/WPSDocument.h
+++ b/inc/libwps/WPSDocument.h
@@ -46,7 +46,7 @@ namespace libwps
enum WPSConfidence { WPS_CONFIDENCE_NONE=0, WPS_CONFIDENCE_EXCELLENT, WPS_CONFIDENCE_SUPPORTED_ENCRYPTION };
enum WPSCreator { WPS_MSWORKS=0 /**< Microsoft Works documents (all wps, wks and wdb) */,
- WPS_LOTUS /**Lotus DOS(Wk1), Apple(Lotus 123 v1), Windows(Wk3,Wk4) spreadsheets*/,
+ WPS_LOTUS /**Lotus DOS(Wk1), Apple(Lotus 123 v1), Windows(Wk3,Wk4,123) spreadsheets*/,
WPS_QUATTRO_PRO /**Quattro Pro Wq1 and Wq2 spreadsheets(minimum filter)*/,
WPS_SYMPHONY /**Lotus Symphony files(untested, probably DOS documents)*/,
WPS_RESERVED_0, WPS_RESERVED_1, WPS_RESERVED_2,
diff --git a/src/lib/Lotus.cpp b/src/lib/Lotus.cpp
index 326bcd0..407606b 100644
--- a/src/lib/Lotus.cpp
+++ b/src/lib/Lotus.cpp
@@ -42,6 +42,7 @@
#include "WPSOLE1Parser.h"
#include "WPSPageSpan.h"
#include "WPSStream.h"
+#include "WPSStringStream.h"
#include "LotusGraph.h"
#include "LotusSpreadsheet.h"
@@ -120,11 +121,12 @@ void SubDocument::parse(shared_ptr<WKSContentListener> &listener, libwps::SubDoc
struct State
{
//! constructor
- explicit State(libwps_tools_win::Font::Type fontType) : m_fontType(fontType), m_version(-1),
+ State(libwps_tools_win::Font::Type fontType, char const *password) : m_fontType(fontType), m_version(-1),
m_inMainContentBlock(false), m_fontsMap(), m_pageSpan(), m_maxSheet(0),
m_actualZoneId(0), m_actualZoneParentId(0), m_sheetZoneIdList(), m_dataZoneIdToSheetZoneIdMap(),
m_actualLevels(), m_zone1Stack(), m_sheetSubZoneOpened(0x20, false), m_actPage(0), m_numPages(0),
- m_headerString(""), m_footerString(""), m_metaData()
+ m_headerString(""), m_footerString(""), m_metaData(),
+ m_password(password), m_isEncrypted(false), m_isDecoded(false)
{
}
//! return the default font style
@@ -249,6 +251,12 @@ struct State
//! the metadata
librevenge::RVNGPropertyList m_metaData;
+ //! the password (if known)
+ char const *m_password;
+ //! true if the file is encrypted
+ bool m_isEncrypted;
+ //! true if the main stream has been decoded
+ bool m_isDecoded;
private:
State(State const &);
State operator=(State const &);
@@ -258,11 +266,12 @@ private:
// constructor, destructor
LotusParser::LotusParser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
- libwps_tools_win::Font::Type encoding) :
+ libwps_tools_win::Font::Type encoding,
+ char const *password) :
WKSParser(input, header), m_listener(), m_state(), m_styleManager(), m_graphParser(), m_spreadsheetParser(), m_ole1Parser()
{
- m_state.reset(new LotusParserInternal::State(encoding));
+ m_state.reset(new LotusParserInternal::State(encoding, password));
m_styleManager.reset(new LotusStyleManager(*this));
m_graphParser.reset(new LotusGraph(*this));
m_spreadsheetParser.reset(new LotusSpreadsheet(*this));
@@ -337,7 +346,7 @@ void LotusParser::parse(librevenge::RVNGSpreadsheetInterface *documentInterface)
throw (libwps::ParseException());
}
- if (!checkHeader(0L, true)) throw(libwps::ParseException());
+ if (!checkHeader(0L)) throw(libwps::ParseException());
bool ok=false;
try
@@ -363,6 +372,12 @@ void LotusParser::parse(librevenge::RVNGSpreadsheetInterface *documentInterface)
ok = true;
}
}
+ catch (libwps::PasswordException())
+ {
+ ascii().reset();
+ WPS_DEBUG_MSG(("LotusParser::parse: password exception catched when parsing MN0\n"));
+ throw (libwps::PasswordException());
+ }
catch (...)
{
WPS_DEBUG_MSG(("LotusParser::parse: exception catched when parsing MN0\n"));
@@ -407,7 +422,7 @@ bool LotusParser::createListener(librevenge::RVNGSpreadsheetInterface *interface
////////////////////////////////////////////////////////////
bool LotusParser::checkHeader(WPSHeader *header, bool strict)
{
- m_state.reset(new LotusParserInternal::State(m_state->m_fontType));
+ m_state.reset(new LotusParserInternal::State(m_state->m_fontType, m_state->m_password));
shared_ptr<WPSStream> mainStream(new WPSStream(getInput(), ascii()));
if (!checkHeader(mainStream, true, strict))
return false;
@@ -417,6 +432,7 @@ bool LotusParser::checkHeader(WPSHeader *header, bool strict)
header->setCreator(libwps::WPS_LOTUS);
header->setKind(libwps::WPS_SPREADSHEET);
header->setNeedEncoding(true);
+ header->setIsEncrypted(m_state->m_isEncrypted);
}
return true;
}
@@ -458,19 +474,13 @@ bool LotusParser::checkHeader(shared_ptr<WPSStream> stream, bool mainStream, boo
}
f << "lotus123[FMT],";
}
- else if (val>=0x1000 && val<=0x1003)
+ else if (val>=0x1000 && val<=0x1005)
{
WPS_DEBUG_MSG(("LotusParser::checkHeader: find lotus123 file\n"));
m_state->m_version=(val-0x1000)+1;
f << "lotus123[" << m_state->m_version << "],";
}
#ifdef DEBUG
- else if (val>0x1003 && val<=0x1005)
- {
- WPS_DEBUG_MSG(("LotusParser::checkHeader: find lotus123 file\n"));
- m_state->m_version=(val-0x1000)+1;
- f << "lotus123[" << m_state->m_version << "],";
- }
else if (val==0x8007)
{
WPS_DEBUG_MSG(("LotusParser::checkHeader: find lotus file format, sorry parsing this file is only implemented for debugging, not output will be created\n"));
@@ -489,6 +499,7 @@ bool LotusParser::checkHeader(shared_ptr<WPSStream> stream, bool mainStream, boo
for (int i=0; i < 4; ++i)
{
if (!readZone(stream)) return false;
+ if (m_state->m_isEncrypted) break;
}
}
ascFile.addPos(0);
@@ -575,7 +586,11 @@ bool LotusParser::readZones(shared_ptr<WPSStream> stream)
if (input->isEnd())
break;
- while (readZone(stream)) ;
+ while (readZone(stream))
+ {
+ if (m_state->m_isEncrypted && !m_state->m_isDecoded)
+ throw(libwps::PasswordException());
+ }
//
// look for ending
@@ -705,6 +720,78 @@ bool LotusParser::readZone(shared_ptr<WPSStream> stream)
case 0x1: // EOF
ok = false;
break;
+ case 0x2:
+ m_state->m_isEncrypted=true;
+ if (sz==16)
+ {
+ input->seek(pos+4, librevenge::RVNG_SEEK_SET);
+ std::vector<uint8_t> fileKeys;
+ for (int i=0; i<16; ++i)
+ {
+ unsigned char c(libwps::readU8(input));
+ fileKeys.push_back(uint8_t(c));
+ }
+ isParsed=needWriteInAscii=true;
+ if (!m_state->m_isDecoded)
+ {
+ static uint8_t const(defValues[])=
+ {
+ 0xb9,0x5f, 0xd7,0x31, 0xdb,0x75, 9,0x72,
+ 0x5d,0x85, 0x32,0x11, 0x5,0x11, 0x58,0
+ };
+ uint16_t key;
+ std::vector<uint8_t> keys;
+ if (m_state->m_password && libwps::encodeLotusPassword(m_state->m_password, key, keys, defValues))
+ {
+ bool passwordOk=fileKeys.size()==keys.size();
+ if (passwordOk)
+ {
+ /* check that the password is ok, normally,
+ all keys must be equal excepted:
+ - fileKey7=key7^(key>>8),
+ - and fileKey13=key13^key.
+
+ This also means that knowing fileKeys,
+ it is possible to retrieve the password
+ if it is short enough.
+ */
+ int numSame=0;
+ for (size_t c=0; c < fileKeys.size(); ++c)
+ {
+ if (keys[c]==fileKeys[c])
+ ++numSame;
+ }
+ passwordOk=numSame>=14;
+ if (!passwordOk)
+ {
+ WPS_DEBUG_MSG(("LotusParser::parse: the password seems bad\n"));
+ }
+ }
+ if (!passwordOk)
+ {
+ keys=retrievePasswordKeys(fileKeys);
+ passwordOk=keys.size()==16;
+ }
+ RVNGInputStreamPtr newInput;
+ if (passwordOk) newInput=decodeStream(input, stream->m_eof, keys);
+ if (newInput)
+ {
+ // let's replace the current input by the decoded input
+ m_state->m_isDecoded=true;
+ stream->m_input=newInput;
+ stream->m_ascii.setStream(newInput);
+ }
+ }
+ }
+ }
+ else
+ {
+ WPS_DEBUG_MSG(("LotusParser::parse: find unexpected password field\n"));
+ throw (libwps::PasswordException());
+ }
+ f.str("");
+ f << "Entries(Password):";
+ break;
case 0x3:
if (sz!=6)
{
@@ -1981,8 +2068,8 @@ bool LotusParser::readSheetZone(shared_ptr<WPSStream> stream)
case 0x84:
case 0x93:
case 0x94:
- case 0x95:
- case 0x96:
+ case 0x95: // column definition
+ case 0x96: // row definition
{
size_t subZId=size_t(id&0x1F);
f << "sheetC" << std::hex << subZId << std::dec << "[" << (m_state->m_sheetSubZoneOpened[subZId] ? "close" : "open") << "],";
@@ -2630,7 +2717,9 @@ bool LotusParser::readZone8(shared_ptr<WPSStream> stream)
input->seek(pos, librevenge::RVNG_SEEK_SET);
WPSVec3i minC, maxC;
m_state->getLevels(minC, maxC);
- return m_spreadsheetParser->readCellsFormat801(stream, minC, maxC);
+ return m_spreadsheetParser->readCellsFormat801
+ (stream, minC, maxC, m_state->m_sheetSubZoneOpened[0x15] ? 0 :
+ m_state->m_sheetSubZoneOpened[0x16] ? 1 : -1);
}
if (libwps::readU8(input)!=8)
{
@@ -2681,7 +2770,10 @@ bool LotusParser::readZone8(shared_ptr<WPSStream> stream)
// 1 already done
case 2: // very often 802 and 803 are close to each other (in the sheet's zone)
case 3:
- f << "zoneA" << id << ",";
+ if (id==2)
+ f << "column[def],";
+ else
+ f << "zoneA" << id << ",";
if (sz!=2)
{
WPS_DEBUG_MSG(("LotusParser::readZone8: the size seems bad for id=%d\n", id));
@@ -2694,6 +2786,8 @@ bool LotusParser::readZone8(shared_ptr<WPSStream> stream)
case 4:
{
f << "zoneA4,";
+ if (m_state->m_sheetSubZoneOpened[0x15]) f << "cols,";
+ else if (m_state->m_sheetSubZoneOpened[0x16]) f << "rows,";
if (sz<4)
{
WPS_DEBUG_MSG(("LotusParser::readZone8: the size seems bad for 804\n"));
@@ -3245,8 +3339,132 @@ bool LotusParser::readChartName(shared_ptr<WPSStream> stream)
}
////////////////////////////////////////////////////////////
-// Unknown
+// decode
////////////////////////////////////////////////////////////
+RVNGInputStreamPtr LotusParser::decodeStream(RVNGInputStreamPtr input, long endPos, std::vector<uint8_t> const &key)
+{
+ if (!input || key.size()!=16)
+ {
+ WPS_DEBUG_MSG(("LotusParser::decodeStream: the arguments seems bad\n"));
+ return RVNGInputStreamPtr();
+ }
+ long actPos=input->tell();
+ input->seek(0,librevenge::RVNG_SEEK_SET);
+ librevenge::RVNGBinaryData data;
+ if (!libwps::readData(input, static_cast<unsigned long>(endPos), data) || long(data.size())!=endPos || !data.getDataBuffer())
+ {
+ WPS_DEBUG_MSG(("LotusParser::decodeStream: can not read the original input\n"));
+ return RVNGInputStreamPtr();
+ }
+ unsigned char *buf=const_cast<unsigned char *>(data.getDataBuffer());
+ input->seek(actPos,librevenge::RVNG_SEEK_SET);
+ uint8_t d7=0;
+ bool transform=true;
+ while (!input->isEnd())
+ {
+ long pos=input->tell();
+ if (pos+4>endPos) break;
+ int type=int(libwps::readU16(input));
+ int sSz=int(libwps::readU16(input));
+ if (pos+4+sSz>endPos)
+ {
+ input->seek(pos,librevenge::RVNG_SEEK_SET);
+ break;
+ }
+ // Special case :
+ // 123 files:
+ // - the style zone (between 0x10e and 0x10f) is not transformed
+ // - the stack1[open|close] field are not transformed
+ if (type==0x10e)
+ transform=false;
+ else if (type==0x10f)
+ transform=true;
+ if (type==0x104 || type==0x105 || !transform)
+ {
+ input->seek(pos+4+sSz,librevenge::RVNG_SEEK_SET);
+ continue;
+ }
+ uint8_t d4=uint8_t(sSz);
+ uint8_t d5=key[13];
+ for (int i=0; i<sSz; ++i)
+ {
+ uint8_t c=uint8_t(libwps::readU8(input));
+ buf[pos+4+i]=(c^key[d7&0xf]);
+ d7=uint8_t(c+d4);
+ d4=uint8_t(d4+d5++);
+ }
+ }
+ if (input->tell()!=endPos)
+ {
+ WPS_DEBUG_MSG(("LotusParser::decodeStream: can not decode the end of the file, data may be bad %lx %lx\n", static_cast<unsigned long>(input->tell()), static_cast<unsigned long>(endPos)));
+ }
+ RVNGInputStreamPtr res(new WPSStringStream(data.getDataBuffer(), static_cast<unsigned int>(endPos)));
+ res->seek(actPos, librevenge::RVNG_SEEK_SET);
+ return res;
+}
+
+std::vector<uint8_t> LotusParser::retrievePasswordKeys(std::vector<uint8_t> const &fileKeys)
+{
+ /* let try to detect short password (|password|<=14) by using the
+ fact that fileKeys differ from the keys in two positions.
+ If the password length is less or equal to 12:
+ Using fileKeys[12] and fileKeys[14], we can "retrieve"
+ the password length. Then knowing this length, fileKeys[14]
+ and fileKeys[15] give us the key. Finally, we can retrieve the
+ password and check if it gives us again fileKeys.
+
+ We can also test password with length 13 or 14 similarly.
+
+ Note: if |password|>14, we can detect it by testing 256*256 posibilities, but :-~
+ */
+ std::vector<uint8_t> res;
+ if (fileKeys.size()!=16)
+ {
+ WPS_DEBUG_MSG(("LotusParser::retrievePasswordKeys: the file keys seems bad\n"));
+ return res;
+ }
+ static uint8_t const(defValues[])=
+ {
+ 0xb9,0x5f, 0xd7,0x31, 0xdb,0x75, 9,0x72,
+ 0x5d,0x85, 0x32,0x11, 0x5,0x11, 0x58,0
+ };
+ std::map<uint8_t,size_t> diffToPosMap;
+ for (size_t i=0; i<14; ++i)
+ diffToPosMap[defValues[i+2]^defValues[i]]=i;
+ uint8_t diff12=fileKeys[12]^fileKeys[14];
+ std::vector<size_t> posToTest;
+ if (diffToPosMap.find(diff12)!=diffToPosMap.end() && diffToPosMap.find(diff12)->second+2<14)
+ {
+ posToTest.push_back(diffToPosMap.find(diff12)->second+2);
+ // defValues[0]^defValues[2]=defValues[1]^defValues[3]=0x6e => we must add by hand this position
+ if (diff12==0x6e)
+ posToTest.push_back(2);
+ }
+ // check also password with length 13 or 14
+ posToTest.push_back(0);
+ posToTest.push_back(1);
+ for (size_t st=0; st<posToTest.size(); ++st)
+ {
+ size_t actPos=posToTest[st];
+ uint16_t key=uint16_t(((fileKeys[14]^defValues[actPos])<<8)|(fileKeys[15]^defValues[actPos+1]));
+ res=fileKeys;
+ res[7]=uint8_t(res[7]^key);
+ res[13]=uint8_t(res[13]^(key>>8));
+ // now build the password
+ std::string password;
+ for (size_t i=0; i<size_t(16-actPos-2); ++i)
+ password+=char(res[i]^(key>>((i%2)==0 ? 8 : 0)));
+ // check if the password is correct
+ uint16_t resKey;
+ std::vector<uint8_t> resKeys;
+ if (libwps::encodeLotusPassword(password.c_str(), resKey, resKeys, defValues) && key==resKey && res==resKeys)
+ {
+ WPS_DEBUG_MSG(("LotusParser::retrievePasswordKeys: Find password %s\n", password.c_str()));
+ return res;
+ }
+ }
+ return std::vector<uint8_t>();
+}
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
diff --git a/src/lib/Lotus.h b/src/lib/Lotus.h
index 69610bb..96abd9e 100644
--- a/src/lib/Lotus.h
+++ b/src/lib/Lotus.h
@@ -72,7 +72,8 @@ class LotusParser : public WKSParser
public:
//! constructor
LotusParser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
- libwps_tools_win::Font::Type encoding=libwps_tools_win::Font::UNKNOWN);
+ libwps_tools_win::Font::Type encoding=libwps_tools_win::Font::UNKNOWN,
+ char const *password=0);
//! destructor
~LotusParser();
//! called by WPSDocument to parse the file
@@ -174,8 +175,12 @@ protected:
//! reads the chart name or title
bool readChartName(shared_ptr<WPSStream> stream);
- //////////////////////// unknown zone //////////////////////////////
+ //////////////////////// decode a stream //////////////////////////////
+ //! try to decode a stream, if successful, replace the stream'input by the new one
+ static RVNGInputStreamPtr decodeStream(RVNGInputStreamPtr input, long endPos, std::vector<uint8_t> const &key);
+ //! try to guess a password knowing its file keys. Returns the keys if it founds a valid password
+ static std::vector<uint8_t> retrievePasswordKeys(std::vector<uint8_t> const &fileKeys);
shared_ptr<WKSContentListener> m_listener; /** the listener (if set)*/
//! the internal state
diff --git a/src/lib/LotusGraph.cpp b/src/lib/LotusGraph.cpp
index c03f43e..f6571ab 100644
--- a/src/lib/LotusGraph.cpp
+++ b/src/lib/LotusGraph.cpp
@@ -334,7 +334,7 @@ struct ZonePc
//! the stream
shared_ptr<WPSStream> m_stream;
//! the bdbox
- WPSBox2i m_box;
+ WPSBox2f m_box;
//! the translation
Vec2f m_translate;
//! the rotation
@@ -365,14 +365,14 @@ bool ZonePc::getGraphicShape(WPSGraphicShape &shape, WPSPosition &pos) const
case Line:
{
// we need to recompute the bdbox
- int bounds[4]= {m_box[0][0],m_box[0][1],m_box[1][0],m_box[1][1]};
+ float bounds[4]= {m_box[0][0],m_box[0][1],m_box[1][0],m_box[1][1]};
for (int i=0; i<2; ++i)
{
if (bounds[i]<=bounds[i+2]) continue;
bounds[i]=bounds[i+2];
bounds[i+2]=m_box[0][i];
}
- WPSBox2i realBox(Vec2i(bounds[0],bounds[1]),Vec2i(bounds[2],bounds[3]));
+ WPSBox2f realBox(Vec2f(bounds[0],bounds[1]),Vec2f(bounds[2],bounds[3]));
pos=WPSPosition(realBox[0],realBox.size(), librevenge::RVNG_POINT);
pos.setRelativePosition(WPSPosition::Page);
shape=WPSGraphicShape::line(m_box[0]-realBox[0], m_box[1]-realBox[0]);
@@ -2014,6 +2014,7 @@ bool LotusGraph::readGraphZone(shared_ptr<WPSStream> stream, int zId)
RVNGInputStreamPtr &input = stream->m_input;
libwps::DebugFile &ascFile=stream->m_ascii;
libwps::DebugStream f;
+ float const unit=version()>=5 ? 1.f/16.f : 1.f/256.f;
long pos = input->tell();
int id = (int) libwps::readU8(input);
if (libwps::readU8(input) != 3)
@@ -2322,7 +2323,7 @@ bool LotusGraph::readGraphZone(shared_ptr<WPSStream> stream, int zId)
f2 << "g" << i << "=" << std::hex << val << std::dec << ",";
}
float translate[2];
- for (int i=0; i<2; ++i) translate[i]=float(libwps::read32(input))/256.f;
+ for (int i=0; i<2; ++i) translate[i]=unit*float(libwps::read32(input));
zone->m_translate=Vec2f(translate[0],translate[1]);
for (int i=0; i<2; ++i)
{
@@ -2347,7 +2348,7 @@ bool LotusGraph::readGraphZone(shared_ptr<WPSStream> stream, int zId)
else
{
float dim[4];
- for (int i=0; i<4; ++i) dim[i]=float(libwps::read32(input))/256.f;
+ for (int i=0; i<4; ++i) dim[i]=unit*float(libwps::read32(input));
zone->m_box=WPSBox2f(Vec2f(dim[0],dim[1]),Vec2f(dim[2],dim[3]));
if (id==0x8b || id==0x8e || id==0x9a)
{
@@ -2443,6 +2444,7 @@ bool LotusGraph::readGraphDataZone(shared_ptr<WPSStream> stream, long endPos)
RVNGInputStreamPtr &input = stream->m_input;
libwps::DebugFile &ascFile=stream->m_ascii;
libwps::DebugStream f;
+ float const unit=version()>=5 ? 1.f/16.f : 1.f/256.f;
f << "Entries(GraphZone)[data]:";
long pos = input->tell();
int sz=int(endPos-pos);
@@ -2450,7 +2452,7 @@ bool LotusGraph::readGraphDataZone(shared_ptr<WPSStream> stream, long endPos)
{
f << "line,";
float dim[4];
- for (int i=0; i<4; ++i) dim[i]=float(libwps::read32(input))/256.f;
+ for (int i=0; i<4; ++i) dim[i]=unit*float(libwps::read32(input));
m_state->m_actualZonePc->m_box= WPSBox2f(Vec2f(dim[0],dim[1]),Vec2f(dim[2],dim[3]));
f << "dim=" << m_state->m_actualZonePc->m_box << ",";
}
@@ -2461,7 +2463,7 @@ bool LotusGraph::readGraphDataZone(shared_ptr<WPSStream> stream, long endPos)
float dim[2];
for (int n=0; n<m_state->m_actualZonePc->m_numPoints; ++n)
{
- for (int i=0; i<2; ++i) dim[i]=float(libwps::read32(input))/256.f;
+ for (int i=0; i<2; ++i) dim[i]=unit*float(libwps::read32(input));
m_state->m_actualZonePc->m_vertices.push_back(Vec2f(dim[0],dim[1]));
f << m_state->m_actualZonePc->m_vertices.back() << ",";
}
diff --git a/src/lib/LotusSpreadsheet.cpp b/src/lib/LotusSpreadsheet.cpp
index 9fb7bc3..7e609df 100644
--- a/src/lib/LotusSpreadsheet.cpp
+++ b/src/lib/LotusSpreadsheet.cpp
@@ -40,6 +40,7 @@
#include "WPSFont.h"
#include "WPSCell.h"
#include "WPSStream.h"
+#include "WPSTable.h"
#include "Lotus.h"
#include "LotusStyleManager.h"
@@ -259,7 +260,7 @@ class Spreadsheet
public:
//! a constructor
Spreadsheet() : m_name(""), m_numCols(0), m_numRows(0), m_boundsColsMap(),
- m_widthColsInChar(), m_rowHeightMap(), m_heightDefault(16),
+ m_widthCols(), m_rowHeightMap(), m_heightDefault(16),
m_rowPageBreaksList(), m_positionToCellMap(), m_rowToStyleIdMap(),
m_rowToExtraStyleMap() {}
//! return a cell corresponding to a spreadsheet, create one if needed
@@ -274,92 +275,97 @@ public:
return m_positionToCellMap.find(pos)->second;
}
//! set the columns size
- void setColumnWidthInChar(int col, float w=-1)
+ void setColumnWidth(int col, WPSColumnFormat const &format)
{
- if (col < 0) return;
- if (col >= int(m_widthColsInChar.size()))
+ if (col >= int(m_widthCols.size()))
{
// sanity check
- if (col>255 && !m_boundsColsMap.empty() && col >= int(m_widthColsInChar.size())+10 &&
+ if (col>255 && !m_boundsColsMap.empty() && col >= int(m_widthCols.size())+10 &&
m_boundsColsMap.find(col)==m_boundsColsMap.end())
{
WPS_DEBUG_MSG(("LotusSpreadsheetInternal::Spreadsheet::setColumnWidth: the column %d seems bad\n", col));
return;
}
- m_widthColsInChar.resize(size_t(col)+1, -1);
+ WPSColumnFormat defCol;
+ defCol.m_useOptimalWidth=true;
+ m_widthCols.resize(size_t(col)+1, defCol);
}
- m_widthColsInChar[size_t(col)] = w;
+ m_widthCols[size_t(col)] = format;
if (col >= m_numCols) m_numCols=col+1;
}
//! returns the row size in point
- float getRowHeight(int row) const
+ WPSRowFormat getRowHeight(int row) const
{
- std::map<Vec2i,int>::const_iterator rIt=m_rowHeightMap.lower_bound(Vec2i(-1,row));
+ std::map<Vec2i,WPSRowFormat>::const_iterator rIt=m_rowHeightMap.lower_bound(Vec2i(-1,row));
if (rIt!=m_rowHeightMap.end() && rIt->first[0]<=row && rIt->first[1]>=row)
- return (float) rIt->second;
- return (float) -m_heightDefault;
+ return rIt->second;
+ WPSRowFormat format(m_heightDefault);
+ format.m_isMinimalHeight=true;
+ return format;
}
//! set the rows size
- void setRowHeight(int row, int h)
+ void setRowHeight(int row, WPSRowFormat const &format)
{
- if (h>=0)
- m_rowHeightMap[Vec2i(row,row)]=h;
+ m_rowHeightMap[Vec2i(row,row)]=format;
}
//! returns the position corresponding to a cell
Vec2f getPosition(Vec2i const &cell) const
{
// first compute the height
int lastRow=0;
- int h=0;
- std::map<Vec2i,int>::const_iterator rIt=m_rowHeightMap.begin();
+ float h=0;
+ std::map<Vec2i,WPSRowFormat>::const_iterator rIt=m_rowHeightMap.begin();
while (rIt!=m_rowHeightMap.end() && rIt->first[1]<cell[1])
{
if (rIt->first[0]>lastRow)
{
- h+=(rIt->first[0]-lastRow)*m_heightDefault;
+ h+=float(rIt->first[0]-lastRow)*m_heightDefault;
lastRow=rIt->first[0];
}
- h+=(rIt->first[1]+1-lastRow)*rIt->second;
+ float rHeight=rIt->second.m_height>=0 ? rIt->second.m_height : m_heightDefault;
+ h+=float(rIt->first[1]+1-lastRow)*rHeight;
lastRow=rIt->first[1]+1;
++rIt;
}
if (lastRow<cell[1])
{
- if (rIt!=m_rowHeightMap.end() && rIt->first[0]<cell[1])
- h+=(cell[1]-lastRow)*rIt->second;
+ if (rIt!=m_rowHeightMap.end() && rIt->first[0]<cell[1] && rIt->second.m_height>=0)
+ h+=float(cell[1]-lastRow)*rIt->second.m_height;
else
- h+=(cell[1]-lastRow)*m_heightDefault;
+ h+=float(cell[1]-lastRow)*m_heightDefault;
}
// now compute the width
- size_t const numCols = m_widthColsInChar.size();
+ size_t const numCols = m_widthCols.size();
float w=0;
for (size_t i = 0; i < numCols && i<size_t(cell[0]); i++)
- w+=m_widthColsInChar[i]>=0 ? 8*m_widthColsInChar[i] : 72;
+ w+=m_widthCols[i].m_width>=0 ? m_widthCols[i].m_width : 72;
if (numCols<size_t(cell[0]))
w+=72*float(size_t(cell[0])-numCols);
- return Vec2f(w, float(h));
+ return Vec2f(w, h);
}
//! try to compress the list of row height
void compressRowHeights()
{
- std::map<Vec2i,int> oldMap=m_rowHeightMap;
+ std::map<Vec2i,WPSRowFormat> oldMap=m_rowHeightMap;
m_rowHeightMap.clear();
- std::map<Vec2i,int>::const_iterator rIt=oldMap.begin();
- int actHeight=-1;
+ std::map<Vec2i,WPSRowFormat>::const_iterator rIt=oldMap.begin();
+ WPSRowFormat actHeight;
+ WPSRowFormat defHeight(m_heightDefault);
+ defHeight.m_isMinimalHeight=true;
Vec2i actPos(0,-1);
while (rIt!=oldMap.end())
{
// first check for not filled row
if (rIt->first[0]!=actPos[1]+1)
{
- if (actHeight==m_heightDefault)
+ if (actHeight==defHeight)
actPos[1]=rIt->first[0]-1;
else
{
if (actPos[1]>=actPos[0])
m_rowHeightMap[actPos]=actHeight;
- actHeight=m_heightDefault;
+ actHeight=defHeight;
actPos=Vec2i(actPos[1]+1, rIt->first[0]-1);
}
}
@@ -377,31 +383,31 @@ public:
m_rowHeightMap[actPos]=actHeight;
}
//! convert the m_widthColsInChar in a vector of of point size
- std::vector<float> getColumnWidths(std::vector<int> &repeated) const
+ std::vector<WPSColumnFormat> getWidths() const
{
- size_t numElt = m_widthColsInChar.size();
- std::vector<float> res;
- size_t actCol=0;
- float prevWidth=-1;
- for (size_t i = 0; i < numElt; i++)
+ std::vector<WPSColumnFormat> widths;
+ WPSColumnFormat defWidth, actWidth;
+ defWidth.m_useOptimalWidth=true;
+ int repeat=0;
+ for (size_t c = 0; c < m_widthCols.size(); c++)
{
- float newVal=m_widthColsInChar[i]>=0 ? m_widthColsInChar[i]*8.f : -1.f;
- if (newVal<=prevWidth && newVal>=prevWidth)
- continue;
- if (actCol!=i)
+ WPSColumnFormat newWidth=m_widthCols[c];
+ if (repeat && newWidth!=actWidth)
{
- res.push_back(prevWidth);
- repeated.push_back(int(i-actCol));
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
+ repeat=0;
}
- actCol=i;
- prevWidth=newVal;
+ if (repeat==0)
+ actWidth=newWidth;
+ ++repeat;
}
- if (actCol<numElt && prevWidth>=0)
+ if (repeat)
{
- res.push_back(prevWidth);
- repeated.push_back(int(numElt-actCol));
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
}
- return res;
+ return widths;
}
//! returns the row style id corresponding to a sheetId (or -1)
int getRowStyleId(int row) const
@@ -425,12 +431,12 @@ public:
int m_numRows;
/** a map used to stored the min/max row of each columns */
std::map<int, Vec2i> m_boundsColsMap;
- /** the column size in char */
- std::vector<float> m_widthColsInChar;
+ /** the column size */
+ std::vector<WPSColumnFormat> m_widthCols;
/** the map Vec2i(min row, max row) to size in points */
- std::map<Vec2i,int> m_rowHeightMap;
+ std::map<Vec2i,WPSRowFormat> m_rowHeightMap;
/** the default row size in point */
- int m_heightDefault;
+ float m_heightDefault;
/** the list of row page break */
std::vector<int> m_rowPageBreaksList;
/** a map cell to not empty cells */
@@ -448,7 +454,7 @@ public:
struct Format123Style : public WPSCellFormat
{
//! constructor
- Format123Style()
+ Format123Style() : m_alignAcrossColumn(false)
{
}
//! update the cell style
@@ -458,6 +464,13 @@ struct Format123Style : public WPSCellFormat
style.setFormat(getFormat(), getSubFormat());
style.setDigits(digits());
}
+ //! operator==
+ bool operator==(Format123Style const &f) const
+ {
+ return m_alignAcrossColumn==f.m_alignAcrossColumn && compare(f)==0;
+ }
+ //! flag to know if we must align across column
+ bool m_alignAcrossColumn;
};
//! the extra style for lotus 123
@@ -478,6 +491,16 @@ struct Extra123Style
}
return true;
}
+ //! operator==
+ bool operator==(Extra123Style const &f) const
+ {
+ for (int i=0; i<2; ++i)
+ {
+ if (m_borders[i]!=f.m_borders[i])
+ return false;
+ }
+ return true;
+ }
//! update the cell style
void update(Style &style) const
{
@@ -508,7 +531,17 @@ struct Table123Styles
{
WPS_DEBUG_MSG(("LotusSpreadsheetInternal::Table123Styles::addCellStyle: find dupplicated cell\n"));
}
- map[cols]=cellId;
+ std::map<Vec2i,int>::iterator it=map.lower_bound(cols);
+ if (!map.empty() && it!=map.begin()) --it;
+ if (it!=map.end() && it->first[1]+1==cols[0] && it->second==cellId)
+ {
+ Vec2i newCols=it->first;
+ map.erase(newCols);
+ newCols[1]=cols[1];
+ map[newCols]=cellId;
+ }
+ else
+ map[cols]=cellId;
}
//! add a extra style to a list of cell
void addCellStyle(Vec2i const &cols, Vec2i const &rows, Extra123Style const &extra)
@@ -517,7 +550,17 @@ struct Table123Styles
m_rowsToColsToExtraStyleMap[rows]= std::map<Vec2i,Extra123Style>();
std::map<Vec2i,Extra123Style> &map=m_rowsToColsToExtraStyleMap.find(rows)->second;
// checkme: sometimes, we can retrieve the same cells again
- map[cols]=extra;
+ std::map<Vec2i,Extra123Style>::iterator it=map.lower_bound(cols);
+ if (!map.empty() && it!=map.begin()) --it;
+ if (it!=map.end() && it->first[1]+1==cols[0] && it->second==extra)
+ {
+ Vec2i newCols=it->first;
+ map.erase(newCols);
+ newCols[1]=cols[1];
+ map[newCols]=extra;
+ }
+ else
+ map[cols]=extra;
}
//! add a extra style to a list of cell
void addCellStyle(Vec2i const &cols, Vec2i const &rows, Format123Style const &format)
@@ -529,7 +572,17 @@ struct Table123Styles
{
WPS_DEBUG_MSG(("LotusSpreadsheetInternal::Table123Styles::addCellStyle: find dupplicated cell\n"));
}
- map[cols]=format;
+ std::map<Vec2i,Format123Style>::iterator it=map.lower_bound(cols);
+ if (!map.empty() && it!=map.begin()) --it;
+ if (it!=map.end() && it->first[1]+1==cols[0] && it->second==format)
+ {
+ Vec2i newCols=it->first;
+ map.erase(newCols);
+ newCols[1]=cols[1];
+ map[newCols]=format;
+ }
+ else
+ map[cols]=format;
}
//! the default cell style
int m_defaultCellId;
@@ -939,7 +992,7 @@ bool LotusSpreadsheet::readColumnSizes(shared_ptr<WPSStream> stream)
{
int col=(int)libwps::readU8(input);
int width=(int)libwps::readU8(input); // width in char, default 12...
- sheet->setColumnWidthInChar(col, float(width));
+ sheet->setColumnWidth(col, WPSColumnFormat(float(7*width)));
f << width << "C:col" << col << ",";
}
f << "],";
@@ -1282,7 +1335,7 @@ bool LotusSpreadsheet::readRowFormat(shared_ptr<WPSStream> stream, LotusSpreadsh
return true;
}
-bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i const &minC, WPSVec3i const &maxC)
+bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i const &minC, WPSVec3i const &maxC, int subZoneId)
{
if (!stream) return false;
RVNGInputStreamPtr &input=stream->m_input;
@@ -1440,7 +1493,11 @@ bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i
if (values[1]&1) f << "neg[value,red],";
if (values[1]&2) f << "add[parenthesis],";
- if (values[1]&0x10) f << "align[accross,column],";
+ if (values[1]&0x10)
+ {
+ format.m_alignAcrossColumn=true;
+ f << "align[across,column],";
+ }
if (values[1]&0x20) f << "hidden,";
values[1] &=0xCC;
for (int i=1; i<4; ++i)
@@ -1517,10 +1574,16 @@ bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i
}
case 12: // column data, in general the fourst one
{
+ if (subZoneId==0) f << "col,";
+ else if (subZoneId==1) f << "row,";
+ else if (subZoneId!=-1)
+ {
+ WPS_DEBUG_MSG(("LotusSpreadsheet::readCellsFormat801: the zone8 id seems bad\n"));
+ f << "###zone15=" << subZoneId << ",";
+ }
int width=-1;
bool isDefault=false;
- bool setWidth=true;
- bool isColumn=false;
+ bool isWidthDef=true;
f << "colUnkn=[";
for (int i=0; i<7; ++i) // f1=[01][04][01], f2: big number, f3=0|1, f4=0|2d|3c|240
{
@@ -1531,31 +1594,25 @@ bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i
if ((val&1)==0)
{
isDefault=true;
- input->seek(endPos, librevenge::RVNG_SEEK_SET);
- break;
+ f << "no[w],";
}
if (val&2) f << "hidden,";
if (val&0x20) f << "page[break],";
if (val&0x40)
{
- setWidth=false;
+ isWidthDef=false;
f << "w[def],";
}
if (val&0x100)
- f << "row,";
- else
- {
- f << "col,";
- isColumn=true;
- }
- val &= 0xFE9D;
- if (val!=1)
+ f << "fl100,";
+ val &= 0xFE9C;
+ if (val)
f << "##fl=" << std::hex << val << std::dec << ",";
}
else if (i==3)
{
width=val;
- if (setWidth)
+ if (!isDefault)
f << "w=" << width << ",";
}
else if (val)
@@ -1564,16 +1621,24 @@ bool LotusSpreadsheet::readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i
f << "_,";
}
f << "],";
- if (isDefault || minC[1]<0 || width<0 || !setWidth) break;
+ if (isDefault || minC[1]<0 || width<0) break;
+ if (subZoneId<0 || subZoneId>1) break;
for (int i=minC[0]; i<=maxC[0]; ++i)
{
LotusSpreadsheetInternal::Spreadsheet &sheet=m_state->getSheet(i);
for (int c=minC[1]; c<=maxC[1]; ++c)
{
- if (isColumn)
- sheet.setColumnWidthInChar(c, vers>=5 ? float(width)/128.f : float(width)/8.f); // checkme
+ if (subZoneId==0)
+ {
+ WPSColumnFormat format(!isWidthDef ? 72 : vers>=5 ? float(width)/16.f : float(width));
+ sheet.setColumnWidth(c, format);
+ }
else
- sheet.setRowHeight(c, int(width+0.5));
+ {
+ WPSRowFormat format(vers>=5 ? float(width)/16.f : float(width));
+ format.m_useOptimalHeight=!isWidthDef;
+ sheet.setRowHeight(c, format);
+ }
}
}
break;
@@ -1669,7 +1734,7 @@ bool LotusSpreadsheet::readRowSizes(shared_ptr<WPSStream> stream, long endPos)
if (val!=0xFFFF)
{
f << "dim=" << float(val+31)/32.f << ",";
- sheet->setRowHeight(row, int((val+31)/32));
+ sheet->setRowHeight(row, WPSRowFormat(float(val+31)/32.f));
}
for (int j=0; j<2; ++j)
{
@@ -1817,7 +1882,7 @@ bool LotusSpreadsheet::readExtraRowFormats(shared_ptr<WPSStream> stream)
LotusSpreadsheetInternal::Spreadsheet &sheet=m_state->getSheet(m_state->m_sheetCurrentId);
int val=int(libwps::readU8(input));
- sheet.setRowHeight(row, val);
+ sheet.setRowHeight(row, WPSRowFormat(float(val)));
if (val!=14) f << "height=" << val << ",";
val=int(libwps::readU8(input)); // 10|80
if (val) f << "f0=" << std::hex << val << std::dec << ",";
@@ -2292,10 +2357,7 @@ void LotusSpreadsheet::sendSpreadsheet(int sheetId)
return;
}
LotusSpreadsheetInternal::Spreadsheet &sheet = m_state->getSheet(sheetId);
- std::vector<int> repeated;
- std::vector<float> colWidths=sheet.getColumnWidths(repeated);
- m_listener->openSheet(colWidths, librevenge::RVNG_POINT,
- repeated, m_state->getSheetName(sheetId));
+ m_listener->openSheet(sheet.getWidths(), m_state->getSheetName(sheetId));
m_mainParser.sendGraphics(sheetId);
sheet.compressRowHeights();
/* create a set to know which row needed to be send, each value of
@@ -2327,7 +2389,7 @@ void LotusSpreadsheet::sendSpreadsheet(int sheetId)
newRowSet.insert(rows[0]);
newRowSet.insert(rows[1]+1);
}
- for (std::map<Vec2i,int>::const_iterator rIt=sheet.m_rowHeightMap.begin();
+ for (std::map<Vec2i,WPSRowFormat>::const_iterator rIt=sheet.m_rowHeightMap.begin();
rIt!=sheet.m_rowHeightMap.end(); ++rIt)
{
Vec2i rows=rIt->first;
@@ -2377,7 +2439,7 @@ void LotusSpreadsheet::sendSpreadsheet(int sheetId)
}
if (sIt==newRowSet.end())
break;
- m_listener->openSheetRow(sheet.getRowHeight(row), librevenge::RVNG_POINT, false, *sIt-row);
+ m_listener->openSheetRow(sheet.getRowHeight(row), *sIt-row);
sendRowContent(sheet, row, table123Styles);
m_listener->closeSheetRow();
}
@@ -2456,6 +2518,8 @@ void LotusSpreadsheet::sendRowContent(LotusSpreadsheetInternal::Spreadsheet cons
std::map<Vec2i, LotusSpreadsheetInternal::Extra123Style>::const_iterator e123It;
std::map<Vec2i, LotusSpreadsheetInternal::Format123Style> colToFormatStyleMap;
std::map<Vec2i, LotusSpreadsheetInternal::Format123Style>::const_iterator f123It;
+
+ std::map<int,int> potentialMergeMap;
if (table123Styles)
{
for (std::map<Vec2i, std::map<Vec2i,int> >::const_iterator rIt=table123Styles->m_rowsToColsToCellIdMap.begin();
@@ -2494,6 +2558,8 @@ void LotusSpreadsheet::sendRowContent(LotusSpreadsheetInternal::Spreadsheet cons
colToFormatStyleMap.insert(std::map<Vec2i, LotusSpreadsheetInternal::Format123Style>::value_type(colIt->first,colIt->second));
newColSet.insert(colIt->first[0]);
newColSet.insert(colIt->first[1]+1);
+ if (colIt->first[0]!=colIt->first[1] && colIt->second.m_alignAcrossColumn)
+ potentialMergeMap[colIt->first[0]]=colIt->first[1]+1;
}
}
c123It=colToCellIdMap.begin();
@@ -2593,7 +2659,28 @@ void LotusSpreadsheet::sendRowContent(LotusSpreadsheetInternal::Spreadsheet cons
}
if (!hasCell && !hasStyle) continue;
if (!hasCell) emptyCell.setPosition(Vec2i(col, row));
- sendCellContent(hasCell ? cIt->second : emptyCell, style, endCol-col);
+ bool canMerge=false;
+ if (hasCell && potentialMergeMap.find(col)!=potentialMergeMap.end())
+ {
+ int newEndCol=potentialMergeMap.find(col)->second;
+ std::map<Vec2i, LotusSpreadsheetInternal::Cell>::const_iterator newCIt=cIt;
+ if (newCIt!=sheet.m_positionToCellMap.end()) ++newCIt;
+ canMerge=(newCIt==sheet.m_positionToCellMap.end() || newCIt->first[1]!=row || newCIt->first[0]>=newEndCol);
+ }
+ if (canMerge)
+ {
+ int newEndCol=potentialMergeMap.find(col)->second;
+ while (colIt!=newColSet.end() && *colIt<newEndCol)
+ {
+ ++colIt;
+ continue;
+ }
+ LotusSpreadsheetInternal::Cell cell=cIt->second;
+ cell.setNumSpannedCells(Vec2i(newEndCol-col,1));
+ sendCellContent(cell, style, 1);
+ }
+ else
+ sendCellContent(hasCell ? cIt->second : emptyCell, style, endCol-col);
}
}
diff --git a/src/lib/LotusSpreadsheet.h b/src/lib/LotusSpreadsheet.h
index 7dd7ec5..9fd437a 100644
--- a/src/lib/LotusSpreadsheet.h
+++ b/src/lib/LotusSpreadsheet.h
@@ -109,7 +109,7 @@ protected:
bool readSheetName1B(shared_ptr<WPSStream> stream, long endPos);
//! reads a cell zone formats: zone 801, lotus 123
- bool readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i const &minC, WPSVec3i const &maxC);
+ bool readCellsFormat801(shared_ptr<WPSStream> stream, WPSVec3i const &minC, WPSVec3i const &maxC, int typeZone);
//! reads the columns definitions
bool readColumnDefinition(shared_ptr<WPSStream> stream);
//! reads the column sizes ( in char )
diff --git a/src/lib/LotusStyleManager.cpp b/src/lib/LotusStyleManager.cpp
index bfc1766..10329ae 100644
--- a/src/lib/LotusStyleManager.cpp
+++ b/src/lib/LotusStyleManager.cpp
@@ -183,7 +183,7 @@ struct CellStyle
explicit CellStyle(libwps_tools_win::Font::Type fontType) :
m_borders(0), m_fontId(0), m_formatId(0),
m_colorStyle(), m_fontStyle(fontType),
- m_hAlign(WPSCellFormat::HALIGN_DEFAULT), m_vAlign(WPSCellFormat::VALIGN_DEFAULT),
+ m_hAlign(WPSCellFormat::HALIGN_DEFAULT), m_vAlign(WPSCellFormat::VALIGN_DEFAULT), m_wrapping(WPSCellFormat::WRAP_DEFAULT),
m_rotation(0), m_extra("")
{
for (int i=0; i<4; ++i)
@@ -243,6 +243,18 @@ struct CellStyle
default:
break; // default
}
+ switch (cell.m_wrapping)
+ {
+ case WPSCellFormat::WRAP_WRAP:
+ o << "wrap,";
+ break;
+ case WPSCellFormat::WRAP_NO_WRAP:
+ o << "wrap[no],";
+ break;
+ case WPSCellFormat::WRAP_DEFAULT:
+ default:
+ break;
+ }
if (cell.m_borders)
{
o << "bord=";
@@ -278,6 +290,8 @@ struct CellStyle
WPSCellFormat::HorizontalAlignment m_hAlign;
//! the vertical align
WPSCellFormat::VerticalAlignment m_vAlign;
+ //! the wrapping
+ WPSCellFormat::Wrapping m_wrapping;
//! the rotation
int m_rotation;
//! the cell border
@@ -1368,7 +1382,13 @@ bool LotusStyleManager::readCellStyleD2Data(LotusStyleManagerInternal::CellStyle
val=int(libwps::readU8(input));
if (val!=255) f << "f0=" << val << ";";
val=int(libwps::readU8(input));
- if (val!=255) font.m_fontId=val;
+ if (val!=255)
+ {
+ font.m_fontId=val;
+ WPSFont defFont;
+ if (m_mainParser.getFont(font.m_fontId, defFont, font.m_fontType))
+ font.m_font.m_name = defFont.m_name;
+ }
val=int(libwps::readU16(input)); // checkme what is this unit? 1de:18, 173: 14, 140: 12?, 778:72
if (val!=0xFFFF)
font.m_font.m_size=double(int(double(val)*3./80.+0.5));
@@ -1499,7 +1519,11 @@ bool LotusStyleManager::readCellStyleD2Data(LotusStyleManagerInternal::CellStyle
cell.m_vAlign=WPSCellFormat::VALIGN_BOTTOM;
break;
}
- if (!(val&0x80)) f << "wrap[text],";
+ if (!(val&0x80))
+ {
+ f << "wrap[text],";
+ cell.m_wrapping=WPSCellFormat::WRAP_WRAP;
+ }
val&=0x7C;
if (val) f << "#vAlign=" << std::hex << val << std::dec << ",";
break;
@@ -2005,6 +2029,8 @@ bool LotusStyleManager::updateCellStyle(int cellId, WPSCellFormat &format,
format.setHAlignement(cellStyle.m_hAlign);
if (cellStyle.m_vAlign!=WPSCellFormat::VALIGN_DEFAULT)
format.setVAlignement(cellStyle.m_vAlign);
+ if (cellStyle.m_wrapping!=WPSCellFormat::WRAP_DEFAULT)
+ format.setWrapping(cellStyle.m_wrapping);
// wk3
if (cellStyle.m_fontId>=0)
{
diff --git a/src/lib/QuattroSpreadsheet.cpp b/src/lib/QuattroSpreadsheet.cpp
index a0d55b2..aaf7f55 100644
--- a/src/lib/QuattroSpreadsheet.cpp
+++ b/src/lib/QuattroSpreadsheet.cpp
@@ -36,6 +36,7 @@
#include "WKSContentListener.h"
#include "WPSEntry.h"
#include "WPSFont.h"
+#include "WPSTable.h"
#include "Quattro.h"
@@ -313,19 +314,36 @@ public:
if (col >= m_numCols) m_numCols=col+1;
}
- //! convert the m_widthCols in a vector of of point size
- static std::vector<float> convertInPoint(std::vector<int> const &list,
- float defSize)
+ //! return the columns format
+ std::vector<WPSColumnFormat> getWidths(float defSize=76) const
{
- size_t numElt = list.size();
- std::vector<float> res;
- res.resize(numElt);
- for (size_t i = 0; i < numElt; i++)
+ std::vector<WPSColumnFormat> widths;
+ WPSColumnFormat defWidth(defSize), actWidth;
+ defWidth.m_useOptimalWidth=true;
+ int repeat=0;
+ for (size_t c = 0; c < m_widthCols.size(); c++)
{
- if (list[i] < 0) res[i] = defSize;
- else res[i] = float(list[i])/20.f;
+ WPSColumnFormat newWidth;
+ if (m_widthCols[c] < 0)
+ newWidth=defWidth;
+ else
+ newWidth=WPSColumnFormat(float(m_widthCols[c])/20.f);
+ if (repeat && newWidth!=actWidth)
+ {
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
+ repeat=0;
+ }
+ if (repeat==0)
+ actWidth=newWidth;
+ ++repeat;
+ }
+ if (repeat)
+ {
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
}
- return res;
+ return widths;
}
//! returns the row size in point
float getRowHeight(int row) const
@@ -2158,8 +2176,7 @@ void QuattroSpreadsheet::sendSpreadsheet(int sId)
sheet.reset(new QuattroSpreadsheetInternal::Spreadsheet);
}
- m_listener->openSheet(sheet->convertInPoint(sheet->m_widthCols,76), librevenge::RVNG_POINT,
- std::vector<int>(), m_state->getSheetName(sId));
+ m_listener->openSheet(sheet->getWidths(), m_state->getSheetName(sId));
sheet->compressRowHeights();
std::map<Vec2i, QuattroSpreadsheetInternal::Cell>::const_iterator it = sheet->m_positionToCellMap.begin();
int prevRow = -1;
@@ -2176,14 +2193,14 @@ void QuattroSpreadsheet::sendSpreadsheet(int sId)
float h=sheet->getRowHeight(prevRow+1, numRepeat);
if (row<prevRow+1+numRepeat)
numRepeat=row-1-prevRow;
- m_listener->openSheetRow(h, librevenge::RVNG_POINT, false, numRepeat);
+ m_listener->openSheetRow(WPSRowFormat(h), numRepeat);
prevRow+=numRepeat;
}
}
if (row!=prevRow)
{
if (prevRow != -1) m_listener->closeSheetRow();
- m_listener->openSheetRow(sheet->getRowHeight(++prevRow), librevenge::RVNG_POINT);
+ m_listener->openSheetRow(WPSRowFormat(sheet->getRowHeight(++prevRow)));
}
sendCellContent(cell);
}
diff --git a/src/lib/WKS4.cpp b/src/lib/WKS4.cpp
index 70ceffc..d9fc262 100644
--- a/src/lib/WKS4.cpp
+++ b/src/lib/WKS4.cpp
@@ -38,6 +38,7 @@
#include "WPSFont.h"
#include "WPSHeader.h"
#include "WPSPageSpan.h"
+#include "WPSStringStream.h"
#include "WKS4Format.h"
#include "WKS4Spreadsheet.h"
@@ -113,10 +114,11 @@ void SubDocument::parse(shared_ptr<WKSContentListener> &listener, libwps::SubDoc
struct State
{
//! constructor
- explicit State(libwps_tools_win::Font::Type fontType) :
+ State(libwps_tools_win::Font::Type fontType, char const *password) :
m_eof(-1), m_creator(libwps::WPS_MSWORKS), m_isSpreadsheet(true), m_fontType(fontType), m_version(-1),
m_hasLICSCharacters(false), m_fontsList(), m_pageSpan(), m_actPage(0), m_numPages(0),
- m_headerString(""), m_footerString("")
+ m_headerString(""), m_footerString(""),
+ m_password(password), m_isEncrypted(false), m_isDecoded(false)
{
}
//! returns a color corresponding to an id
@@ -164,6 +166,17 @@ struct State
std::string m_headerString;
//! the footer string
std::string m_footerString;
+
+ //! the password (if known)
+ char const *m_password;
+ //! true if the file is encrypted
+ bool m_isEncrypted;
+ //! true if the main stream has been decoded
+ bool m_isDecoded;
+
+private:
+ State(State const &);
+ State &operator=(State const &);
};
bool State::getColor(int id, WPSColor &color) const
@@ -206,11 +219,11 @@ bool State::getColor(int id, WPSColor &color) const
// constructor, destructor
WKS4Parser::WKS4Parser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
- libwps_tools_win::Font::Type encoding) :
+ libwps_tools_win::Font::Type encoding, char const *password) :
WKSParser(input, header), m_listener(), m_state(), m_spreadsheetParser()
{
- m_state.reset(new WKS4ParserInternal::State(encoding));
+ m_state.reset(new WKS4ParserInternal::State(encoding, password));
m_spreadsheetParser.reset(new WKS4Spreadsheet(*this));
}
@@ -223,6 +236,13 @@ int WKS4Parser::version() const
return m_state->m_version;
}
+void WKS4Parser::resetMainInput(RVNGInputStreamPtr newInput)
+{
+ resetInput(newInput);
+ ascii().setStream(newInput);
+ m_spreadsheetParser->resetInput(newInput);
+}
+
bool WKS4Parser::checkFilePosition(long pos)
{
if (m_state->m_eof < 0)
@@ -284,7 +304,7 @@ void WKS4Parser::parse(librevenge::RVNGSpreadsheetInterface *documentInterface)
throw (libwps::ParseException());
}
- if (!checkHeader(0L, true)) throw(libwps::ParseException());
+ if (!checkHeader(0L)) throw(libwps::ParseException());
bool ok=false;
try
@@ -311,6 +331,12 @@ void WKS4Parser::parse(librevenge::RVNGSpreadsheetInterface *documentInterface)
ok = true;
}
}
+ catch (libwps::PasswordException())
+ {
+ ascii().reset();
+ WPS_DEBUG_MSG(("WKS4Parser::parse: password exception catched when parsing MN0\n"));
+ throw (libwps::PasswordException());
+ }
catch (...)
{
WPS_DEBUG_MSG(("WKS4Parser::parse: exception catched when parsing MN0\n"));
@@ -349,7 +375,7 @@ shared_ptr<WKSContentListener> WKS4Parser::createListener(librevenge::RVNGSpread
////////////////////////////////////////////////////////////
bool WKS4Parser::checkHeader(WPSHeader *header, bool strict)
{
- *m_state = WKS4ParserInternal::State(m_state->m_fontType);
+ m_state.reset(new WKS4ParserInternal::State(m_state->m_fontType, m_state->m_password));
libwps::DebugStream f;
RVNGInputStreamPtr input = getInput();
@@ -456,25 +482,27 @@ bool WKS4Parser::checkHeader(WPSHeader *header, bool strict)
return false;
}
+ m_state->m_creator=creator;
input->seek(0, librevenge::RVNG_SEEK_SET);
if (strict && m_state->m_version<1000)
{
for (int i=0; i < 4; ++i)
{
if (!readZone()) return false;
+ if (m_state->m_isEncrypted) break;
}
}
ascii().addPos(0);
ascii().addNote(f.str().c_str());
m_state->m_isSpreadsheet=isSpreadsheet;
- m_state->m_creator=creator;
if (header)
{
header->setMajorVersion((uint8_t) m_state->m_version);
header->setCreator(creator);
header->setKind(kind);
header->setNeedEncoding(needEncoding);
+ header->setIsEncrypted(m_state->m_isEncrypted);
}
return true;
}
@@ -513,11 +541,16 @@ bool WKS4Parser::readZones()
return false;
}
- while (readZone()) ;
+ while (readZone())
+ {
+ if (m_state->m_isEncrypted && !m_state->m_isDecoded)
+ throw(libwps::PasswordException());
+ }
//
// look for ending
//
+ input = getInput();
long pos = input->tell();
if (!checkFilePosition(pos+4))
{
@@ -782,6 +815,50 @@ bool WKS4Parser::readZone()
readChartName();
isParsed = true;
break;
+ case 0x4b:
+ if (sz==2 && m_state->m_creator==libwps::WPS_LOTUS)
+ {
+ m_state->m_isEncrypted=true;
+ input->seek(pos+4, librevenge::RVNG_SEEK_SET);
+ f.str("");
+ uint16_t fileKey(libwps::readU16(input));
+ f << "Entries(Password):pass=" << std::hex << fileKey << std::dec << ",";
+ isParsed = needWriteInAscii = true;
+ if (!m_state->m_isDecoded)
+ {
+ static uint8_t const(defValues[])=
+ {
+ 0xbb,0xff, 0xff,0xba, 0xff,0xff, 0xb9,0x80,
+ 0,0x0be, 0xf,0, 0xbf,0xf, 0,0
+ };
+ uint16_t key;
+ std::vector<uint8_t> keys;
+ if (m_state->m_password && libwps::encodeLotusPassword(m_state->m_password, key, keys, defValues))
+ {
+ RVNGInputStreamPtr newInput;
+ if (uint16_t(key<<8|key>>8)==fileKey)
+ newInput=decodeStream(input, m_state->m_eof, keys);
+ if (newInput)
+ {
+ // let's replace the current input by the decoded input
+ m_state->m_isDecoded=true;
+ input=newInput;
+ resetMainInput(newInput);
+ }
+ else
+ {
+ WPS_DEBUG_MSG(("LotusParser::parse: the password seems bad\n"));
+ }
+
+ }
+ }
+ break;
+ }
+ else
+ {
+ WPS_DEBUG_MSG(("LotusParser::parse: find unexpected password field\n"));
+ }
+ break;
case 0x64: // hidden column
isParsed = m_spreadsheetParser->readHiddenColumns();
break;
@@ -2083,4 +2160,52 @@ bool WKS4Parser::readUnknown1()
return true;
}
+////////////////////////////////////////////////////////////
+// decode
+////////////////////////////////////////////////////////////
+RVNGInputStreamPtr WKS4Parser::decodeStream(RVNGInputStreamPtr input, long endPos, std::vector<uint8_t> const &key)
+{
+ if (!input || key.size()!=16)
+ {
+ WPS_DEBUG_MSG(("WKS4Parser::decodeStream: the arguments seems bad\n"));
+ return RVNGInputStreamPtr();
+ }
+ long actPos=input->tell();
+ input->seek(0,librevenge::RVNG_SEEK_SET);
+ librevenge::RVNGBinaryData data;
+ if (!libwps::readDataToEnd(input, data) || long(data.size())!=endPos || !data.getDataBuffer())
+ {
+ WPS_DEBUG_MSG(("WKS4Parser::decodeStream: can not read the original input\n"));
+ return RVNGInputStreamPtr();
+ }
+ unsigned char *buf=const_cast<unsigned char *>(data.getDataBuffer());
+ input->seek(actPos,librevenge::RVNG_SEEK_SET);
+ uint8_t d7=0;
+ while (!input->isEnd())
+ {
+ long pos=input->tell();
+ if (pos+4>endPos) break;
+ input->seek(2,librevenge::RVNG_SEEK_CUR);
+ int sSz=int(libwps::readU16(input));
+ if (pos+4+sSz>endPos)
+ {
+ input->seek(pos,librevenge::RVNG_SEEK_SET);
+ break;
+ }
+ for (int i=0; i<sSz; ++i)
+ {
+ uint8_t c=uint8_t(libwps::readU8(input));
+ c=uint8_t((c<<1)|(c>>7));
+ c=(c^key[(d7++)&0xf]);
+ buf[pos+4+i]=uint8_t((c>>6)|(c<<2));
+ }
+ }
+ if (input->tell()!=endPos)
+ {
+ WPS_DEBUG_MSG(("WKS4Parser::decodeStream: can not decode the end of the file, data may be bad %lx %lx\n", static_cast<unsigned long>(input->tell()), static_cast<unsigned long>(endPos)));
+ }
+ RVNGInputStreamPtr res(new WPSStringStream(data.getDataBuffer(), static_cast<unsigned int>(endPos)));
+ res->seek(actPos, librevenge::RVNG_SEEK_SET);
+ return res;
+}
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
diff --git a/src/lib/WKS4.h b/src/lib/WKS4.h
index cac0c86..97fff70 100644
--- a/src/lib/WKS4.h
+++ b/src/lib/WKS4.h
@@ -51,7 +51,8 @@ class WKS4Parser : public WKSParser
public:
//! constructor
WKS4Parser(RVNGInputStreamPtr &input, WPSHeaderPtr &header,
- libwps_tools_win::Font::Type encoding=libwps_tools_win::Font::UNKNOWN);
+ libwps_tools_win::Font::Type encoding=libwps_tools_win::Font::UNKNOWN,
+ char const *password=0);
//! destructor
~WKS4Parser();
//! called by WPSDocument to parse the file
@@ -94,6 +95,8 @@ protected:
/// check for the existence of a format stream, if it exists, parse it
bool parseFormatStream();
+ /// reset the main input
+ void resetMainInput(RVNGInputStreamPtr newInput);
/** finds the different zones (spreadsheet, chart, print, ...) */
bool readZones();
@@ -142,6 +145,11 @@ protected:
//! reads an unknown structure which seems relative to a chart : CHECKME
bool readChartUnknown();
+ //////////////////////// decode a lotus stream //////////////////////////////
+
+ //! try to decode a stream, if successful, replace the stream'input by the new one
+ static RVNGInputStreamPtr decodeStream(RVNGInputStreamPtr input, long endPos, std::vector<uint8_t> const &key);
+
//////////////////////// unknown zone //////////////////////////////
//! reads windows record 0:7|0:9
diff --git a/src/lib/WKS4Spreadsheet.cpp b/src/lib/WKS4Spreadsheet.cpp
index 90a2734..29dd98e 100644
--- a/src/lib/WKS4Spreadsheet.cpp
+++ b/src/lib/WKS4Spreadsheet.cpp
@@ -36,6 +36,7 @@
#include "WKSContentListener.h"
#include "WPSEntry.h"
#include "WPSFont.h"
+#include "WPSTable.h"
#include "WKS4.h"
@@ -337,19 +338,36 @@ public:
if (actPos[1]>=actPos[0])
m_rowHeightMap[actPos]=actHeight;
}
- //! convert the m_widthCols in a vector of of point size
- static std::vector<float> convertInPoint(std::vector<int> const &list,
- float defSize)
+ //! return the columns format
+ std::vector<WPSColumnFormat> getWidths(float defSize=72) const
{
- size_t numElt = list.size();
- std::vector<float> res;
- res.resize(numElt);
- for (size_t i = 0; i < numElt; i++)
+ std::vector<WPSColumnFormat> widths;
+ WPSColumnFormat defWidth(defSize), actWidth;
+ defWidth.m_useOptimalWidth=true;
+ int repeat=0;
+ for (size_t c = 0; c < m_widthCols.size(); c++)
{
- if (list[i] < 0) res[i] = defSize;
- else res[i] = float(list[i])/20.f;
+ WPSColumnFormat newWidth;
+ if (m_widthCols[c] < 0)
+ newWidth=defWidth;
+ else
+ newWidth=WPSColumnFormat(float(m_widthCols[c])/20.f);
+ if (repeat && newWidth!=actWidth)
+ {
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
+ repeat=0;
+ }
+ if (repeat==0)
+ actWidth=newWidth;
+ ++repeat;
+ }
+ if (repeat)
+ {
+ actWidth.m_numRepeat=repeat;
+ widths.push_back(actWidth);
}
- return res;
+ return widths;
}
//! returns true if the spreedsheet is empty
bool empty() const
@@ -475,6 +493,11 @@ WKS4Spreadsheet::~WKS4Spreadsheet()
{
}
+void WKS4Spreadsheet::resetInput(RVNGInputStreamPtr newInput)
+{
+ m_input=newInput;
+}
+
int WKS4Spreadsheet::version() const
{
if (m_state->m_version<0)
@@ -2322,8 +2345,7 @@ void WKS4Spreadsheet::sendSpreadsheet(int sId)
sheet.reset(new WKS4SpreadsheetInternal::Spreadsheet);
}
- m_listener->openSheet(sheet->convertInPoint(sheet->m_widthCols,72), librevenge::RVNG_POINT,
- std::vector<int>(), m_state->getSheetName(sId));
+ m_listener->openSheet(sheet->getWidths(), m_state->getSheetName(sId));
sheet->compressRowHeights();
std::map<Vec2i, WKS4SpreadsheetInternal::Cell>::const_iterator it = sheet->m_positionToCellMap.begin();
int prevRow = -1;
@@ -2340,14 +2362,14 @@ void WKS4Spreadsheet::sendSpreadsheet(int sId)
float h=sheet->getRowHeight(prevRow+1, numRepeat);
if (row<prevRow+1+numRepeat)
numRepeat=row-1-prevRow;
- m_listener->openSheetRow(h, librevenge::RVNG_POINT, false, numRepeat);
+ m_listener->openSheetRow(WPSRowFormat(h), numRepeat);
prevRow+=numRepeat;
}
}
if (row!=prevRow)
{
if (prevRow != -1) m_listener->closeSheetRow();
- m_listener->openSheetRow(sheet->getRowHeight(++prevRow), librevenge::RVNG_POINT);
+ m_listener->openSheetRow(WPSRowFormat(sheet->getRowHeight(++prevRow)));
}
sendCellContent(cell);
}
diff --git a/src/lib/WKS4Spreadsheet.h b/src/lib/WKS4Spreadsheet.h
index ebacf69..0b128a0 100644
--- a/src/lib/WKS4Spreadsheet.h
+++ b/src/lib/WKS4Spreadsheet.h
@@ -67,6 +67,8 @@ protected:
int version() const;
//! returns the true if the file has LICS characters
bool hasLICSCharacters() const;
+ /// reset the main input
+ void resetInput(RVNGInputStreamPtr input);
//! returns the number of spreadsheet
int getNumSpreadsheets() const;
diff --git a/src/lib/WKSContentListener.cpp b/src/lib/WKSContentListener.cpp
index 3b2a40b..08d8209 100644
--- a/src/lib/WKSContentListener.cpp
+++ b/src/lib/WKSContentListener.cpp
@@ -40,6 +40,7 @@
#include "WPSPageSpan.h"
#include "WPSParagraph.h"
#include "WPSPosition.h"
+#include "WPSTable.h"
#include "WKSSubDocument.h"
////////////////////////////////////////////////////////////
@@ -919,8 +920,7 @@ void WKSContentListener::_endSubDocument()
///////////////////
// sheet
///////////////////
-void WKSContentListener::openSheet(std::vector<float> const &colWidth, librevenge::RVNGUnit unit,
- std::vector<int> const &repeatColWidthNumber, librevenge::RVNGString const &name)
+void WKSContentListener::openSheet(std::vector<WPSColumnFormat> const &colList, librevenge::RVNGString const &name)
{
if (m_ps->m_isSheetOpened)
{
@@ -941,21 +941,10 @@ void WKSContentListener::openSheet(std::vector<float> const &colWidth, libreveng
librevenge::RVNGPropertyListVector columns;
- size_t nCols = colWidth.size();
- bool useRepeated=repeatColWidthNumber.size()==nCols;
- if (!useRepeated&&!repeatColWidthNumber.empty())
- {
- WPS_DEBUG_MSG(("WKSContentListener::openSheet: repeatColWidthNumber seems bad\n"));
- }
- for (size_t c = 0; c < nCols; c++)
+ for (size_t c = 0; c < colList.size(); c++)
{
librevenge::RVNGPropertyList column;
- if (colWidth[c]>=0)
- column.insert("style:column-width", colWidth[c], unit);
- else
- column.insert("style:use-optimal-column-width", true);
- if (useRepeated && repeatColWidthNumber[c]>1)
- column.insert("table:number-columns-repeated", repeatColWidthNumber[c]);
+ colList[c].addTo(column);
columns.append(column);
}
propList.insert("librevenge:columns", columns);
@@ -980,7 +969,7 @@ void WKSContentListener::closeSheet()
_popParsingState();
}
-void WKSContentListener::openSheetRow(float h, librevenge::RVNGUnit unit, bool headerRow, int numRepeated)
+void WKSContentListener::openSheetRow(WPSRowFormat const &format, int numRepeated)
{
if (m_ps->m_isSheetRowOpened)
{
@@ -993,14 +982,9 @@ void WKSContentListener::openSheetRow(float h, librevenge::RVNGUnit unit, bool h
return;
}
librevenge::RVNGPropertyList propList;
- propList.insert("librevenge:is-header-row", headerRow);
+ format.addTo(propList);
if (numRepeated>1)
propList.insert("table:number-rows-repeated", numRepeated);
-
- if (h > 0)
- propList.insert("style:row-height", h, unit);
- else if (h < 0)
- propList.insert("style:min-row-height", -h, unit);
m_documentInterface->openSheetRow(propList);
m_ps->m_isSheetRowOpened = true;
}
@@ -1231,6 +1215,7 @@ shared_ptr<WKSContentParsingState> WKSContentListener::_pushParsingState()
m_ps->m_pageMarginBottom = actual->m_pageMarginBottom;
m_ps->m_isNote = actual->m_isNote;
+ m_ps->m_isPageSpanOpened = actual->m_isPageSpanOpened;
return actual;
}
diff --git a/src/lib/WKSContentListener.h b/src/lib/WKSContentListener.h
index 4dd0471..4b0c739 100644
--- a/src/lib/WKSContentListener.h
+++ b/src/lib/WKSContentListener.h
@@ -37,11 +37,13 @@
#include "WPSListener.h"
class WPSCellFormat;
+struct WPSColumnFormat;
class WPSGraphicShape;
class WPSGraphicStyle;
class WPSList;
class WPSPageSpan;
struct WPSParagraph;
+struct WPSRowFormat;
struct WPSTabStop;
struct WKSContentParsingState;
@@ -199,12 +201,11 @@ public:
// ------- sheet -----------------
/** open a sheet*/
- void openSheet(std::vector<float> const &colWidth, librevenge::RVNGUnit unit,
- std::vector<int> const &repeatColWidthNumber=std::vector<int>(), librevenge::RVNGString const &name="");
+ void openSheet(std::vector<WPSColumnFormat> const &columns, librevenge::RVNGString const &name="");
/** closes this sheet */
void closeSheet();
- /** open a row with given height. If h<0, use min-row-heigth */
- void openSheetRow(float h, librevenge::RVNGUnit unit, bool headerRow=false, int numRepeated=1);
+ /** open a row */
+ void openSheetRow(WPSRowFormat const &f, int numRepeated=1);
/** closes this row */
void closeSheetRow();
/** low level function to define a cell.
diff --git a/src/lib/WKSParser.h b/src/lib/WKSParser.h
index 7ad43a7..13717fd 100644
--- a/src/lib/WKSParser.h
+++ b/src/lib/WKSParser.h
@@ -42,6 +42,10 @@ protected:
{
return m_input;
}
+ void resetInput(RVNGInputStreamPtr newInput)
+ {
+ m_input=newInput;
+ }
RVNGInputStreamPtr getFileInput();
WPSHeaderPtr &getHeader()
{
diff --git a/src/lib/WPSCell.cpp b/src/lib/WPSCell.cpp
index 6b2e3d9..7086140 100644
--- a/src/lib/WPSCell.cpp
+++ b/src/lib/WPSCell.cpp
@@ -189,7 +189,20 @@ void WPSCellFormat::addTo(librevenge::RVNGPropertyList &propList) const
case VALIGN_DEFAULT:
break; // default
default:
- WPS_DEBUG_MSG(("MWAWCell::addTo: called with unknown valign=%d\n", vAlignement()));
+ WPS_DEBUG_MSG(("WPSCell::addTo: called with unknown valign=%d\n", vAlignement()));
+ }
+ switch (wrapping())
+ {
+ case WRAP_WRAP:
+ propList.insert("fo:wrap-option", "wrap");
+ break;
+ case WRAP_NO_WRAP:
+ propList.insert("fo:wrap-option", "no-wrap");
+ break;
+ case WRAP_DEFAULT:
+ break;
+ default:
+ WPS_DEBUG_MSG(("WPSCell::addTo: called with unknown wrapping=%d\n", wrapping()));
}
if (m_rotation)
propList.insert("style:rotation-angle",m_rotation);
@@ -220,6 +233,7 @@ void WPSCellFormat::addTo(librevenge::RVNGPropertyList &propList) const
propList.insert("fo:background-color", backgroundColor().str().c_str());
if (m_protected)
propList.insert("style:cell-protect","protected");
+ propList.insert("fo:padding",0,librevenge::RVNG_POINT); // changme
}
std::string WPSCellFormat::getValueType() const
@@ -357,6 +371,8 @@ int WPSCellFormat::compare(WPSCellFormat const &cell, bool onlyNumbering) const
if (diff) return diff;
diff = int(m_vAlign) - int(cell.m_vAlign);
if (diff) return diff;
+ diff = int(m_wrapping) - int(cell.m_wrapping);
+ if (diff) return diff;
if (m_rotation<cell.m_rotation) return 1;
if (m_rotation>cell.m_rotation) return -1;
if (m_backgroundColor<cell.m_backgroundColor) return 1;
@@ -408,6 +424,18 @@ std::ostream &operator<<(std::ostream &o, WPSCellFormat const &cell)
default:
break; // default
}
+ switch (cell.m_wrapping)
+ {
+ case WPSCellFormat::WRAP_WRAP:
+ o << "wrap,";
+ break;
+ case WPSCellFormat::WRAP_NO_WRAP:
+ o << "wrap[no],";
+ break;
+ case WPSCellFormat::WRAP_DEFAULT:
+ default:
+ break;
+ }
if (cell.m_rotation)
o << "rotation=" << cell.m_rotation << ",";
int subForm = cell.m_subFormat;
diff --git a/src/lib/WPSCell.h b/src/lib/WPSCell.h
index 76bdd9c..1cf4ab7 100644
--- a/src/lib/WPSCell.h
+++ b/src/lib/WPSCell.h
@@ -48,7 +48,8 @@ public:
};
/** the default vertical alignement. */
enum VerticalAlignment { VALIGN_TOP, VALIGN_CENTER, VALIGN_BOTTOM, VALIGN_DEFAULT };
-
+ /** the wrapping */
+ enum Wrapping { WRAP_WRAP, WRAP_NO_WRAP, WRAP_DEFAULT };
/** the different types of cell's field */
enum FormatType { F_TEXT, F_BOOLEAN, F_NUMBER, F_DATE, F_TIME, F_UNKNOWN };
@@ -66,7 +67,7 @@ public:
//! constructor
WPSCellFormat() :
- m_font(), m_hAlign(HALIGN_DEFAULT), m_vAlign(VALIGN_DEFAULT), m_rotation(0), m_bordersList(), m_format(F_UNKNOWN), m_subFormat(0), m_DTFormat(""), m_digits(-1000), m_protected(false), m_backgroundColor(WPSColor::white()) { }
+ m_font(), m_hAlign(HALIGN_DEFAULT), m_vAlign(VALIGN_DEFAULT), m_wrapping(WRAP_DEFAULT), m_rotation(0), m_bordersList(), m_format(F_UNKNOWN), m_subFormat(0), m_DTFormat(""), m_digits(-1000), m_protected(false), m_backgroundColor(WPSColor::white()) { }
//! destructor
virtual ~WPSCellFormat() {}
//! returns true if this is a basic format style
@@ -112,6 +113,16 @@ public:
{
m_vAlign = align;
}
+ //! returns the wrapping
+ Wrapping wrapping() const
+ {
+ return m_wrapping;
+ }
+ //! sets the wrapping
+ void setWrapping(Wrapping align)
+ {
+ m_wrapping = align;
+ }
//! returns the text rotation angle
int getTextRotation() const
@@ -240,6 +251,8 @@ protected:
HorizontalAlignment m_hAlign;
//! the cell vertical alignement : by default nothing
VerticalAlignment m_vAlign;
+ //! the wrapping : by default nothing
+ Wrapping m_wrapping;
//! the text rotation
int m_rotation;
//! the cell border WPSBorder::Pos
diff --git a/src/lib/WPSDocument.cpp b/src/lib/WPSDocument.cpp
index 52a0e66..615b8b4 100644
--- a/src/lib/WPSDocument.cpp
+++ b/src/lib/WPSDocument.cpp
@@ -105,7 +105,7 @@ WPSLIB WPSConfidence WPSDocument::isFileFormatSupported(librevenge::RVNGInputStr
if (!parser.checkHeader(header.get(), true))
return WPS_CONFIDENCE_NONE;
needEncoding=header->getNeedEncoding();
- return WPS_CONFIDENCE_EXCELLENT;
+ return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT;
}
else if (kind==WPS_SPREADSHEET && creator==WPS_QUATTRO_PRO && header->getMajorVersion()<=2)
{
@@ -123,7 +123,7 @@ WPSLIB WPSConfidence WPSDocument::isFileFormatSupported(librevenge::RVNGInputStr
if (!parser.checkHeader(header.get(), true))
return WPS_CONFIDENCE_NONE;
needEncoding=header->getNeedEncoding();
- return WPS_CONFIDENCE_EXCELLENT;
+ return header->getIsEncrypted() ? WPS_CONFIDENCE_SUPPORTED_ENCRYPTION : WPS_CONFIDENCE_EXCELLENT;
}
/* A word document: as WPS8Parser does not have a checkHeader
@@ -145,6 +145,10 @@ WPSLIB WPSConfidence WPSDocument::isFileFormatSupported(librevenge::RVNGInputStr
{
WPS_DEBUG_MSG(("File exception trapped\n"));
}
+ catch (libwps::PasswordException)
+ {
+ WPS_DEBUG_MSG(("Password exception trapped\n"));
+ }
catch (libwps::ParseException)
{
WPS_DEBUG_MSG(("Parse exception trapped\n"));
@@ -228,6 +232,11 @@ WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge:
WPS_DEBUG_MSG(("Parse exception trapped\n"));
error = WPS_PARSE_ERROR;
}
+ catch (libwps::PasswordException)
+ {
+ WPS_DEBUG_MSG(("Password exception trapped\n"));
+ error = WPS_ENCRYPTION_ERROR;
+ }
catch (...)
{
//fixme: too generic
@@ -239,7 +248,7 @@ WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge:
}
WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge::RVNGSpreadsheetInterface *documentInterface,
- char const * /*password*/, char const *encoding)
+ char const *password, char const *encoding)
{
if (!ip || !documentInterface)
return WPS_UNKNOWN_ERROR;
@@ -260,7 +269,7 @@ WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge:
header->getMajorVersion()>=100)
{
parser.reset(new LotusParser(header->getInput(), header,
- libwps_tools_win::Font::getTypeForString(encoding)));
+ libwps_tools_win::Font::getTypeForString(encoding), password));
if (!parser) return WPS_UNKNOWN_ERROR;
parser->parse(documentInterface);
}
@@ -282,7 +291,7 @@ WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge:
case 1:
{
parser.reset(new WKS4Parser(header->getInput(), header,
- libwps_tools_win::Font::getTypeForString(encoding)));
+ libwps_tools_win::Font::getTypeForString(encoding), password));
if (!parser) return WPS_UNKNOWN_ERROR;
parser->parse(documentInterface);
break;
@@ -304,6 +313,11 @@ WPSLIB WPSResult WPSDocument::parse(librevenge::RVNGInputStream *ip, librevenge:
WPS_DEBUG_MSG(("Parse exception trapped\n"));
error = WPS_PARSE_ERROR;
}
+ catch (libwps::PasswordException)
+ {
+ WPS_DEBUG_MSG(("Password exception trapped\n"));
+ error = WPS_ENCRYPTION_ERROR;
+ }
catch (...)
{
//fixme: too generic
diff --git a/src/lib/WPSHeader.cpp b/src/lib/WPSHeader.cpp
index f20b7c1..05e680d 100644
--- a/src/lib/WPSHeader.cpp
+++ b/src/lib/WPSHeader.cpp
@@ -30,7 +30,7 @@ using namespace libwps;
WPSHeader::WPSHeader(RVNGInputStreamPtr &input, RVNGInputStreamPtr &fileInput, uint8_t majorVersion, WPSKind kind, WPSCreator creator) :
m_input(input), m_fileInput(fileInput), m_majorVersion(majorVersion), m_kind(kind), m_creator(creator),
- m_needEncodingFlag(false)
+ m_isEncrypted(false), m_needEncodingFlag(false)
{
}
diff --git a/src/lib/WPSHeader.h b/src/lib/WPSHeader.h
index 289adaf..21c97fb 100644
--- a/src/lib/WPSHeader.h
+++ b/src/lib/WPSHeader.h
@@ -66,6 +66,16 @@ public:
m_kind=kind;
}
+ bool getIsEncrypted() const
+ {
+ return m_isEncrypted;
+ }
+
+ void setIsEncrypted(bool isEncrypted)
+ {
+ m_isEncrypted=isEncrypted;
+ }
+
bool getNeedEncoding() const
{
return m_needEncodingFlag;
@@ -94,6 +104,8 @@ private:
uint8_t m_majorVersion;
libwps::WPSKind m_kind;
libwps::WPSCreator m_creator;
+ //! a flag to know if the file is encrypted
+ bool m_isEncrypted;
//! a flag to know if we need to have the character set encoding
bool m_needEncodingFlag;
};
diff --git a/src/lib/WPSTable.cpp b/src/lib/WPSTable.cpp
index 040ab0b..0e13b50 100644
--- a/src/lib/WPSTable.cpp
+++ b/src/lib/WPSTable.cpp
@@ -38,6 +38,65 @@
#include "WPSTable.h"
////////////////////////////////////////////////////////////
+// WPSColumnFormat
+std::ostream &operator<<(std::ostream &o, WPSColumnFormat const &column)
+{
+ if (column.m_width>=0)
+ {
+ if (column.m_isPercentWidth)
+ o<<"w=" << column.m_width << "%,";
+ else
+ o<<"w=" << column.m_width << ",";
+ }
+ if (column.m_useOptimalWidth) o << "optimal[h],";
+ if (column.m_isHeader) o << "table[header],";
+ if (column.m_numRepeat>1) o << "repeat=" << column.m_numRepeat << ",";
+ return o;
+}
+
+void WPSColumnFormat::addTo(librevenge::RVNGPropertyList &propList) const
+{
+ if (m_width>=0)
+ propList.insert("style:column-width", m_width, m_isPercentWidth ? librevenge::RVNG_PERCENT : librevenge::RVNG_POINT);
+ if (m_useOptimalWidth)
+ propList.insert("style:use-optimal-column-width", true);
+ if (m_isHeader)
+ propList.insert("librevenge:is-header-column", true); // checkme
+ if (m_numRepeat>1)
+ propList.insert("table:number-columns-repeated", m_numRepeat);
+}
+
+////////////////////////////////////////////////////////////
+// WPSRowFormat
+std::ostream &operator<<(std::ostream &o, WPSRowFormat const &row)
+{
+ if (row.m_height>=0)
+ {
+ if (row.m_isMinimalHeight)
+ o<<"h[min]=" << row.m_height << ",";
+ else
+ o<<"h=" << row.m_height << ",";
+ }
+ if (row.m_useOptimalHeight) o << "optimal[h],";
+ if (row.m_isHeader) o << "table[header],";
+ return o;
+}
+
+void WPSRowFormat::addTo(librevenge::RVNGPropertyList &propList) const
+{
+ if (m_height>=0)
+ {
+ if (m_isMinimalHeight)
+ propList.insert("style:min-row-height", m_height, librevenge::RVNG_POINT);
+ else
+ propList.insert("style:row-height", m_height, librevenge::RVNG_POINT);
+ }
+ if (m_useOptimalHeight)
+ propList.insert("style:use-optimal-row-height", true);
+ propList.insert("librevenge:is-header-row", m_isHeader);
+}
+
+////////////////////////////////////////////////////////////
// destructor, ...
WPSTable::~WPSTable()
{
diff --git a/src/lib/WPSTable.h b/src/lib/WPSTable.h
index f871e7d..0d00f20 100644
--- a/src/lib/WPSTable.h
+++ b/src/lib/WPSTable.h
@@ -32,6 +32,123 @@
#include "libwps_internal.h"
/*
+ * Structure to store the column properties
+ *
+ * \note use only to define sheet properties, to be changed
+ */
+struct WPSColumnFormat
+{
+public:
+ //! constructor
+ explicit WPSColumnFormat(float width=-1)
+ : m_width(width)
+ , m_isPercentWidth(false)
+ , m_useOptimalWidth(false)
+ , m_isHeader(false)
+ , m_numRepeat(1)
+ {
+ }
+ //! add to the propList
+ void addTo(librevenge::RVNGPropertyList &propList) const;
+ /** a comparison function
+ \note this comparison function does ignore m_numRepeat
+ */
+ int compare(WPSColumnFormat const &col) const
+ {
+ if (m_width<col.m_width) return 1;
+ if (m_width>col.m_width) return -1;
+ if (m_isPercentWidth!=col.m_isPercentWidth) return m_isPercentWidth ? 1 : -1;
+ if (m_useOptimalWidth!=col.m_useOptimalWidth) return m_useOptimalWidth ? 1 : -1;
+ if (m_isHeader!=col.m_isHeader) return m_isHeader ? 1 : -1;
+ return 0;
+ }
+ //! operator==
+ bool operator==(WPSColumnFormat const &col) const
+ {
+ return compare(col)==0;
+ }
+ //! operator!=
+ bool operator!=(WPSColumnFormat const &col) const
+ {
+ return compare(col)!=0;
+ }
+ //! operator<
+ bool operator<(WPSColumnFormat const &col) const
+ {
+ return compare(col)<0;
+ }
+ //! operator<<
+ friend std::ostream &operator<<(std::ostream &o, WPSColumnFormat const &col);
+
+ //! the column width, if known
+ float m_width;
+ //! a flag to know if the width is in percent (or in point)
+ bool m_isPercentWidth;
+ //! a flag to know if we need to see use-optimal column width
+ bool m_useOptimalWidth;
+ //! a flag to know if the column is a header column
+ bool m_isHeader;
+ //! the number times a column is repeated
+ int m_numRepeat;
+};
+
+/*
+ * Structure to store the row properties
+ *
+ * \note use only to define sheet properties, to be changed
+ */
+struct WPSRowFormat
+{
+public:
+ //! constructor
+ explicit WPSRowFormat(float height=-1)
+ : m_height(height)
+ , m_isMinimalHeight(false)
+ , m_useOptimalHeight(false)
+ , m_isHeader(false)
+ {
+ }
+ //! add to the propList
+ void addTo(librevenge::RVNGPropertyList &propList) const;
+ //! a comparison function
+ int compare(WPSRowFormat const &row) const
+ {
+ if (m_height<row.m_height) return 1;
+ if (m_height>row.m_height) return -1;
+ if (m_isMinimalHeight!=row.m_isMinimalHeight) return m_isMinimalHeight ? 1 : -1;
+ if (m_useOptimalHeight!=row.m_useOptimalHeight) return m_useOptimalHeight ? 1 : -1;
+ if (m_isHeader!=row.m_isHeader) return m_isHeader ? 1 : -1;
+ return 0;
+ }
+ //! operator==
+ bool operator==(WPSRowFormat const &row) const
+ {
+ return compare(row)==0;
+ }
+ //! operator!=
+ bool operator!=(WPSRowFormat const &row) const
+ {
+ return compare(row)!=0;
+ }
+ //! operator<
+ bool operator<(WPSRowFormat const &row) const
+ {
+ return compare(row)<0;
+ }
+ //! operator<<
+ friend std::ostream &operator<<(std::ostream &o, WPSRowFormat const &row);
+
+ //! the row height, if known
+ float m_height;
+ //! a flag to know if the height is only a minimum
+ bool m_isMinimalHeight;
+ //! a flag to know if we need to see use-optimal row height
+ bool m_useOptimalHeight;
+ //! a flag to know if the row is a header row
+ bool m_isHeader;
+};
+
+/*
* Structure to store and construct a table from an unstructured list
* of cell
*
diff --git a/src/lib/libwps_internal.cpp b/src/lib/libwps_internal.cpp
index 0aae7d6..73d1999 100644
--- a/src/lib/libwps_internal.cpp
+++ b/src/lib/libwps_internal.cpp
@@ -825,6 +825,64 @@ bool WPSTransformation::decompose(float &rot, Vec2f &shearing, WPSTransformation
transform=WPSTransformation::rotation(-rot, center) * transform;
return true;
}
+
+////////////////////////////////////////////////////////////
+// password utility
+////////////////////////////////////////////////////////////
+
+namespace libwps
+{
+//! try to encode a lotus file
+bool encodeLotusPassword(char const *password, uint16_t &key, std::vector<uint8_t> &keys, uint8_t const(&defValues)[16])
+{
+ if (!password)
+ {
+ WPS_DEBUG_MSG(("libwps::encodeLotusPassword: called without password\n"));
+ return false;
+ }
+ size_t const len=16;
+ key=0xFFFF;
+ uint16_t val=0;
+ for (size_t i=0; i<len; ++i)
+ {
+ if (password[i]==0)
+ break;
+ uint8_t c=uint8_t(password[i]);
+ key=uint16_t(key^c);
+ val=uint16_t((val&0xFF)|(key<<8));
+ val=uint16_t(((val<<4)&0xFFF0)|(val>>12));
+ key^=val;
+ val=uint16_t((val<<8)|(val>>8));
+ val=uint16_t((val<<1)|(val>>15));
+ val=uint16_t((val<<8)|(val>>8));
+ key=uint16_t((key<<8)|(key>>8));
+ key^=val;
+
+ val=uint16_t((((val>>4)&0xfff)|(val<<12))&0xe0ff);
+ key^=val;
+ val=uint16_t((val>>1)|(val<<15));
+ key=uint16_t(key^(val>>8));
+ }
+
+ size_t cPos;
+ keys.resize(len);
+ // copy password in keys and fill the remaining space with
+ // defValues
+ for (cPos=0 ; cPos<len; ++cPos)
+ {
+ if (password[cPos]==0)
+ break;
+ keys[cPos]=uint8_t(password[cPos]);
+ }
+ uint8_t const *defPtr=defValues;
+ for (; cPos<len; ++cPos)
+ keys[cPos] = *(defPtr++);
+ // now do an xor to code the result
+ for (size_t i=0; i<len; ++i)
+ keys[i]=uint8_t(keys[i]^(key>>((i%2)==0 ? 8 : 0)));
+ return true;
+}
+}
////////////////////////////////////////////////////////////
// debug
////////////////////////////////////////////////////////////
diff --git a/src/lib/libwps_internal.h b/src/lib/libwps_internal.h
index 4df266d..690dedb 100644
--- a/src/lib/libwps_internal.h
+++ b/src/lib/libwps_internal.h
@@ -151,6 +151,11 @@ class ParseException
// needless to say, we could flesh this class out a bit
};
+class PasswordException
+{
+ // needless to say, we could flesh this class out a bit
+};
+
class GenericException
{
// needless to say, we could flesh this class out a bit
@@ -1222,5 +1227,15 @@ protected:
//! flag to know if this matrix is an identity matrix
mutable bool m_isIdentity;
};
+
+//
+// password utility
+//
+
+namespace libwps
+{
+//! try to encode a lotus file
+bool encodeLotusPassword(char const *password, uint16_t &key, std::vector<uint8_t> &keys, uint8_t const(&defValues)[16]);
+}
#endif /* LIBWPS_INTERNAL_H */
/* vim:set shiftwidth=4 softtabstop=4 noexpandtab: */
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-openoffice/libwps.git
More information about the Pkg-openoffice-commits
mailing list