1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <sal/config.h>
21 #include <sal/log.hxx>
22
23 #include <qproform.hxx>
24 #include <qpro.hxx>
25 #include <qprostyle.hxx>
26
27 #include <scerrors.hxx>
28 #include <ftools.hxx>
29 #include <document.hxx>
30 #include <formulacell.hxx>
31 #include <tools/stream.hxx>
32 #include <unotools/configmgr.hxx>
33 #include <docoptio.hxx>
34 #include <scdll.hxx>
35 #include <memory>
36
readSheet(SCTAB nTab,ScDocument * pDoc,ScQProStyle * pStyle)37 ErrCode ScQProReader::readSheet( SCTAB nTab, ScDocument* pDoc, ScQProStyle *pStyle )
38 {
39 ErrCode eRet = ERRCODE_NONE;
40 sal_uInt8 nCol, nDummy;
41 sal_uInt16 nRow;
42 sal_uInt16 nStyle;
43 bool bEndOfSheet = false;
44
45 SAL_INFO("sc", "Read sheet " << nTab);
46
47 while( ERRCODE_NONE == eRet && !bEndOfSheet && nextRecord() )
48 {
49 switch( getId() )
50 {
51 case 0x000f:{ // Label cell
52 mpStream->ReadUChar( nCol ).ReadUChar( nDummy ).ReadUInt16( nRow ).ReadUInt16( nStyle ).ReadUChar( nDummy );
53 sal_uInt16 nLen = getLength();
54 if (nLen >= 7)
55 {
56 OUString aLabel(readString(nLen - 7));
57 nStyle = nStyle >> 3;
58 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
59 pDoc->EnsureTable(nTab);
60 pDoc->SetTextCell(ScAddress(nCol,nRow,nTab), aLabel);
61 }
62 else
63 eRet = SCERR_IMPORT_FORMAT;
64 }
65 break;
66
67 case 0x00cb: // End of sheet
68 bEndOfSheet = true;
69 break;
70
71 case 0x000c: // Blank cell
72 mpStream->ReadUChar( nCol ).ReadUChar( nDummy ).ReadUInt16( nRow ).ReadUInt16( nStyle );
73 nStyle = nStyle >> 3;
74 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
75 break;
76
77 case 0x000d:{ // Integer cell
78 sal_Int16 nValue;
79 mpStream->ReadUChar( nCol ).ReadUChar( nDummy ).ReadUInt16( nRow ).ReadUInt16( nStyle ).ReadInt16( nValue );
80 nStyle = nStyle >> 3;
81 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
82 pDoc->EnsureTable(nTab);
83 pDoc->SetValue(ScAddress(nCol,nRow,nTab), static_cast<double>(nValue));
84 }
85 break;
86
87 case 0x000e:{ // Floating point cell
88 double nValue;
89 mpStream->ReadUChar( nCol ).ReadUChar( nDummy ).ReadUInt16( nRow ).ReadUInt16( nStyle ).ReadDouble( nValue );
90 nStyle = nStyle >> 3;
91 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
92 pDoc->EnsureTable(nTab);
93 pDoc->SetValue(ScAddress(nCol,nRow,nTab), nValue);
94 }
95 break;
96
97 case 0x0010:
98 {
99 // Formula cell
100 double nValue;
101 sal_uInt16 nState, nLen;
102 mpStream->ReadUChar( nCol ).ReadUChar( nDummy ).ReadUInt16( nRow ).ReadUInt16( nStyle ).ReadDouble( nValue ).ReadUInt16( nState ).ReadUInt16( nLen );
103 if (!mpStream->good())
104 {
105 eRet = SCERR_IMPORT_FORMAT;
106 break;
107 }
108 ScAddress aAddr( nCol, nRow, nTab );
109 std::unique_ptr<ScTokenArray> pArray;
110
111 QProToSc aConv(*mpStream, pDoc->GetSharedStringPool(), aAddr);
112 if (ConvErr::OK != aConv.Convert( pArray ))
113 eRet = SCERR_IMPORT_FORMAT;
114 else
115 {
116 ScFormulaCell* pFormula = new ScFormulaCell(pDoc, aAddr, std::move(pArray));
117 nStyle = nStyle >> 3;
118 pFormula->AddRecalcMode( ScRecalcMode::ONLOAD_ONCE );
119 pStyle->SetFormat( pDoc, nCol, nRow, nTab, nStyle );
120 pDoc->EnsureTable(nTab);
121 pDoc->SetFormulaCell(ScAddress(nCol,nRow,nTab), pFormula);
122 }
123 }
124 break;
125 }
126 }
127 return eRet;
128 }
129
ScImportQuattroPro(SvStream * pStream,ScDocument * pDoc)130 ErrCode ScFormatFilterPluginImpl::ScImportQuattroPro(SvStream *pStream, ScDocument *pDoc)
131 {
132 ScQProReader aReader(pStream);
133 ErrCode eRet = aReader.import( pDoc );
134 return eRet;
135 }
136
ScQProReader(SvStream * pStream)137 ScQProReader::ScQProReader(SvStream* pStream)
138 : mnId(0)
139 , mnLength(0)
140 , mnOffset(0)
141 , mpStream(pStream)
142 , mbEndOfFile(false)
143 , mnMaxTab(utl::ConfigManager::IsFuzzing() ? 128 : MAXTAB)
144 {
145 if( mpStream )
146 {
147 mpStream->SetBufferSize( 65535 );
148 mpStream->SetStreamCharSet( RTL_TEXTENCODING_MS_1252 );
149 }
150 }
151
~ScQProReader()152 ScQProReader::~ScQProReader()
153 {
154 if( mpStream )
155 mpStream->SetBufferSize( 0 );
156 }
157
parse(ScDocument * pDoc)158 ErrCode ScQProReader::parse( ScDocument *pDoc )
159 {
160 ErrCode eRet = ERRCODE_NONE;
161 sal_uInt16 nVersion;
162 sal_uInt16 i = 1, j = 1;
163 SCTAB nTab = 0;
164 SetEof( false );
165
166 if( !recordsLeft() )
167 return SCERR_IMPORT_OPEN;
168
169 std::unique_ptr<ScQProStyle> pStyleElement( new ScQProStyle );
170
171 while( nextRecord() && eRet == ERRCODE_NONE)
172 {
173 switch( getId() )
174 {
175 case 0x0000: // Beginning of file
176 mpStream->ReadUInt16( nVersion );
177 break;
178
179 case 0x00ca: // Beginning of sheet
180 if (nTab <= mnMaxTab)
181 {
182 if( nTab < 26 )
183 {
184 OUString aName = OUStringChar( sal_Unicode('A' + nTab) );
185 if (!nTab)
186 pDoc->RenameTab( nTab, aName );
187 else
188 pDoc->InsertTab( nTab, aName );
189 }
190 eRet = readSheet( nTab, pDoc, pStyleElement.get() );
191 nTab++;
192 }
193 break;
194
195 case 0x0001: // End of file
196 SetEof( true );
197 break;
198
199 case 0x00ce:{ // Attribute cell
200 sal_uInt8 nFormat, nAlign, nFont;
201 sal_Int16 nColor;
202 mpStream->ReadUChar( nFormat ).ReadUChar( nAlign ).ReadInt16( nColor ).ReadUChar( nFont );
203 pStyleElement->setAlign( i, nAlign );
204 pStyleElement->setFont( i, nFont );
205 i++;
206 }
207 break;
208
209 case 0x00cf:{ // Font description
210 sal_uInt16 nPtSize, nFontAttr;
211 OUString aLabel;
212 mpStream->ReadUInt16( nPtSize ).ReadUInt16( nFontAttr );
213 pStyleElement->setFontRecord( j, nFontAttr, nPtSize );
214 sal_uInt16 nLen = getLength();
215 if (nLen >= 4)
216 aLabel = readString(nLen - 4);
217 else
218 eRet = SCERR_IMPORT_FORMAT;
219 pStyleElement->setFontType( j, aLabel );
220 j++;
221 }
222 break;
223 }
224 }
225 return eRet;
226 }
227
import(ScDocument * pDoc)228 ErrCode ScQProReader::import( ScDocument *pDoc )
229 {
230 ErrCode eRet = parse(pDoc);
231 pDoc->CalcAfterLoad();
232 return eRet;
233 }
234
TestImportQPW(SvStream & rStream)235 extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportQPW(SvStream &rStream)
236 {
237 ScDLL::Init();
238 ScDocument aDocument;
239 ScDocOptions aDocOpt = aDocument.GetDocOptions();
240 aDocOpt.SetLookUpColRowNames(false);
241 aDocument.SetDocOptions(aDocOpt);
242 aDocument.MakeTable(0);
243 aDocument.EnableExecuteLink(false);
244 aDocument.SetInsertingFromOtherDoc(true);
245 aDocument.SetImportingXML(true);
246 aDocument.SetHardRecalcState(ScDocument::HardRecalcState::ETERNAL);
247
248 ScQProReader aReader(&rStream);
249 ErrCode eRet = aReader.parse(&aDocument);
250 return eRet == ERRCODE_NONE;
251 }
252
recordsLeft()253 bool ScQProReader::recordsLeft()
254 {
255 return mpStream && mpStream->good();
256 }
257
nextRecord()258 bool ScQProReader::nextRecord()
259 {
260 if( !recordsLeft() )
261 return false;
262
263 if( mbEndOfFile )
264 return false;
265
266 sal_uInt32 nPos = mpStream->Tell();
267 if( nPos != mnOffset + mnLength )
268 mpStream->Seek( mnOffset + mnLength );
269
270 mnLength = mnId = 0;
271 mpStream->ReadUInt16( mnId ).ReadUInt16( mnLength );
272
273 mnOffset = mpStream->Tell();
274 #ifdef DEBUG_SC_QPRO
275 fprintf( stderr, "Read record 0x%x length 0x%x at offset 0x%x\n",
276 (unsigned)mnId, (unsigned)mnLength, (unsigned)mnOffset );
277
278 #if 1 // rather verbose
279 int len = mnLength;
280 while (len > 0) {
281 int i, chunk = std::min(len, 16);
282 unsigned char data[16];
283 mpStream->Read( data, chunk );
284
285 for (i = 0; i < chunk; i++)
286 fprintf( stderr, "%.2x ", data[i] );
287 fprintf( stderr, "| " );
288 for (i = 0; i < chunk; i++)
289 fprintf( stderr, "%c", data[i] < 127 && data[i] > 30 ? data[i] : '.' );
290 fprintf( stderr, "\n" );
291
292 len -= chunk;
293 }
294 mpStream->Seek( mnOffset );
295 #endif
296 #endif
297 return true;
298 }
299
readString(sal_uInt16 nLength)300 OUString ScQProReader::readString(sal_uInt16 nLength)
301 {
302 return read_uInt8s_ToOUString(*mpStream, nLength, mpStream->GetStreamCharSet());
303 }
304
305 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
306