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