1 /*
2  *  Copyright (c) 2001 Graham Short.  <grahshrt@netscape.net>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <qpro/common.h>
20 
21 #include <string.h>
22 
23 #include <iostream>
24 
25 #include <qpro/record.h>
26 #include <qpro/formula.h>
27 
28 // -----------------------------------------------------------------------
29 
30 #include <iomanip>
31 #include <sstream>
32 
33 void
Charout(ostream & pOut,unsigned char pChar)34 Charout(ostream& pOut, unsigned char pChar)
35 {
36     pOut << ((pChar < 32) || (pChar > 126) ? '.' : (char)pChar);
37 }
38 
39 void
Hexout(ostream & pOut,unsigned char pChar)40 Hexout(ostream& pOut, unsigned char pChar)
41 {
42     pOut << setiosflags(ios::uppercase)
43     << setfill('0')
44     << setw(2)
45     << hex
46     << (int)pChar
47     << dec;
48 }
49 
50 int
Hexout(char * pChar,int pLen)51 Hexout(char* pChar, int pLen)
52 {
53     std::ostringstream*   lOStr = new std::ostringstream;
54 
55     while (pLen) {
56         int lIdx = 0;
57 
58         for (lIdx = 0; lIdx < 16; ++lIdx) {
59             if (pLen) {
60                 Hexout(cerr, *pChar);
61                 cerr << (lIdx == 8 ? "-" : " ");
62                 Charout(*lOStr, (unsigned char)*pChar);
63                 ++pChar;
64                 --pLen;
65             } else {
66                 cerr << "   ";
67             }
68         }
69 
70         cerr << lOStr->rdbuf() << endl;
71 
72         delete lOStr;
73         lOStr = new std::ostringstream;
74     }
75 
76     delete lOStr;
77     lOStr = 0;
78 
79     return 0;
80 }
81 
82 // -----------------------------------------------------------------------
83 
QpRec(QpRecType pType)84 QpRec::QpRec(QpRecType pType)
85         : cType(pType)
86 {
87 }
88 
~QpRec()89 QpRec::~QpRec()
90 {
91 }
92 
93 QP_INT16
type()94 QpRec::type()
95 {
96     return cType;
97 }
98 
99 // -----------------------------------------------------------------------
100 //
101 //
102 //QpCellRef::QpCellRef(QpIStream& pIn)
103 //{
104 //   pIn >> cNoteBook >> cColumn >> cPage >> cRow;
105 //
106 //QP_DEBUG("CellRef: NoteBook" << cNoteBook << ", col "
107 //         << cColumn << ", Page " << (int)cPage << ", Row "
108 //         << cRow << endl
109 //        );
110 //}
111 //
112 //QpCellRef::~QpCellRef()
113 //{
114 //}
115 //
116 //QP_UINT8
117 //QpCellRef::column()
118 //{
119 //   return cColumn;
120 //}
121 //
122 //QP_INT16
123 //QpCellRef::row()
124 //{
125 //   return cRow;
126 //}
127 //
128 // -----------------------------------------------------------------------
129 
QpRecCell(QpRecType pType)130 QpRecCell::QpRecCell(QpRecType pType)
131         : QpRec(pType)
132         , cAttributes(0)
133         , cColumn(0)
134         , cPage(0)
135         , cRow(0)
136         , cCellRef(0)
137 {
138 }
139 
~QpRecCell()140 QpRecCell::~QpRecCell()
141 {
142     delete [] cCellRef;
143     cCellRef = 0;
144 }
145 
146 
147 void
attributes(QP_INT16 pAttributes)148 QpRecCell::attributes(QP_INT16 pAttributes)
149 {
150     cAttributes = pAttributes;
151 }
152 
153 QP_INT16
attributes()154 QpRecCell::attributes()
155 {
156     return cAttributes;
157 }
158 
159 void
column(QP_UINT8 pColumn)160 QpRecCell::column(QP_UINT8 pColumn)
161 {
162     cColumn = pColumn;
163 }
164 
165 QP_UINT8
column()166 QpRecCell::column()
167 {
168     return cColumn;
169 }
170 
171 void
row(QP_INT16 pRow)172 QpRecCell::row(QP_INT16 pRow)
173 {
174     cRow = pRow;
175 }
176 
177 QP_INT16
row()178 QpRecCell::row()
179 {
180     return cRow;
181 }
182 
183 int
loadCellInfo(QpIStream & pIn)184 QpRecCell::loadCellInfo(QpIStream& pIn)
185 {
186     pIn >> cColumn >> cPage >> cRow >> cAttributes;
187 
188     QP_DEBUG(" col " << (unsigned)cColumn << ", Page " << (unsigned)cPage
189              << ", Row " << cRow << ", Ref "
190              << /*???cellRef()
191             <<*/ ", Attr " << cAttributes
192             );
193 
194     return 6;  // number of bytes consumed
195 }
196 
197 //const char*
198 //QpRecCell::cellRef()
199 //{
200 //  if( cCellRef == 0 )
201 //  {
202 //     cCellRef = new char[20]; // hardcoded len???
203 //
204 /// ??? what value should notebook param be?
205 //     cellRef( cCellRef, 0, 0, cColumn, cRow ); //hardcoded page no. ?????
206 //  }
207 //
208 //  return cCellRef;
209 //
210 
211 void
cellRef(char * pText,QpTableNames & pTable,QP_INT16,QP_UINT8 pPage,QP_UINT8 pColumn,QP_INT16 pRow)212 QpRecCell::cellRef(char* pText, QpTableNames& pTable, QP_INT16 /*pNoteBook*/, QP_UINT8 pPage, QP_UINT8 pColumn, QP_INT16 pRow)
213 {
214 //??? cope with relative/absolute references
215 
216     std::ostringstream lOut;
217     int       lPageRelative = pRow & 0x8000;
218     int       lColRelative  = pRow & 0x4000;
219     int       lRowRelative  = pRow & 0x2000;
220     QP_UINT8  lCol          = (lColRelative ? cColumn + pColumn : pColumn);
221 
222     // Sign bit for row is in bit 0x1000, so either set all top bits or lose all top bits
223     QP_INT16  lRow = (lRowRelative ? cRow + (pRow & 0x1000 ? pRow | 0xE000 : pRow & 0x1FFF)
224                               : pRow & 0x1FFF
225                              );
226 
227     // Are we referencing a different page ?
228 
229     if (lPageRelative && (pPage == 0)) {
230         // no - page is zero relative to this one
231     } else if (pPage != cPage) {
232         // yes - not relative & page is a different one
233 
234         QP_UINT8 lPage = (lPageRelative ? pPage + cPage : pPage);
235 
236         QP_DEBUG("pTable.name((unsigned)lPage) = " <<  pTable.name((unsigned)lPage) << endl);
237 
238         lOut << pTable.name((unsigned)lPage) << '!'; // is '!' compat with QPRO???
239     }
240 
241     if (!lColRelative) {
242         lOut << '$';
243     }
244     if (lCol < 26) {
245         lOut << (char)('A' + lCol);
246     } else {
247         lOut << (char)('A' - 1 + lCol / 26)
248         << (char)('A' + lCol % 26);
249     }
250 
251     if (!lRowRelative) {
252         lOut << '$';
253     }
254 
255     lOut << (lRow & 0x1FFF) + 1;
256     strncpy(pText, lOut.str().c_str(), 20);// ??? ard coded len
257 }
258 
259 void
cellRef(char * pText,QpTableNames & pTable,QpIStream & pFormulaRef)260 QpRecCell::cellRef(char* pText, QpTableNames& pTable, QpIStream& pFormulaRef)
261 {
262     QP_INT16 lNoteBook;
263     pFormulaRef >> lNoteBook;
264 
265     // block references (eg. A1..A9) have bit 0x1000 set
266 
267     if (lNoteBook & 0x1000) {
268         QP_UINT8 lFirstColumn;
269         QP_UINT8 lFirstPage;
270         QP_INT16 lFirstRow;
271         QP_UINT8 lLastColumn;
272         QP_UINT8 lLastPage;
273         QP_INT16 lLastRow;
274 
275         pFormulaRef >> lFirstColumn
276         >> lFirstPage
277         >> lFirstRow
278         >> lLastColumn
279         >> lLastPage
280         >> lLastRow;
281 
282         QP_DEBUG("BlockRef: NoteBook " << lNoteBook
283                  << ", 1st col " << lFirstColumn
284                  << ", 1st page " << (unsigned)lFirstPage
285                  << ", 1st row " << lFirstRow
286                  << ", last col " << lLastColumn
287                  << ", last page " << (unsigned)lLastPage
288                  << ", last row " << lLastRow
289                  << endl
290                 );
291 // ??? next few lines shouldn't just add rows together
292         cellRef(pText, pTable, lNoteBook, lFirstPage, lFirstColumn, lFirstRow);
293 // ?? temp next line      strcat( pText, ".." );
294         strcat(pText, ":");
295         cellRef(&pText[strlen(pText)], pTable, lNoteBook, lLastPage, lLastColumn, lLastRow);
296     } else {
297         QP_UINT8 lColumn;
298         QP_UINT8 lPage;
299         QP_INT16 lRow;
300 
301         pFormulaRef >> lColumn >> lPage >> lRow;
302 
303         QP_DEBUG("FormulaRef: NoteBook " << lNoteBook << ", Col " << (unsigned)lColumn
304                  << ", Page " << (unsigned)lPage << ", Row " << lRow << endl
305                 );
306 
307 // ??? sort out what to do about lNotebook
308 // ??? next few lines shouldn't just add rows together
309         cellRef(pText, pTable, lNoteBook, lPage, lColumn, lRow);
310     }
311 }
312 
313 // -----------------------------------------------------------------------
314 
QpRecBof(QP_INT16,QpIStream & pIn)315 QpRecBof::QpRecBof(QP_INT16, QpIStream& pIn)
316         : QpRec(QpBof)
317 {
318     pIn >> cFileFormat;
319 
320     QP_DEBUG("BOF fileformat=" << cFileFormat << endl);
321 }
322 
~QpRecBof()323 QpRecBof::~QpRecBof()
324 {
325 }
326 
327 // -----------------------------------------------------------------------
328 
QpRecEof(QP_INT16,QpIStream &)329 QpRecEof::QpRecEof(QP_INT16, QpIStream&)
330         : QpRec(QpEof)
331 {
332     QP_DEBUG("EOF" << endl);
333 }
334 
~QpRecEof()335 QpRecEof::~QpRecEof()
336 {
337 }
338 
339 
340 // -----------------------------------------------------------------------
341 
QpRecRecalcMode(QP_INT16,QpIStream & pIn)342 QpRecRecalcMode::QpRecRecalcMode(QP_INT16, QpIStream& pIn)
343         : QpRec(QpRecalcMode)
344 {
345     QP_INT8 lMode;
346 
347     pIn >> lMode;
348 
349     cMode = (MODE)(unsigned char) lMode;
350 
351     QP_DEBUG("Recalc Mode = "
352              << (int)lMode << (cMode == Manual ? " (Manual)"
353                                : cMode == Background ? " (Background)"
354                                : cMode == Automatic  ? " (Automatic)"
355                                : " (Unknown)"
356                               )
357              << endl
358             );
359 }
360 
~QpRecRecalcMode()361 QpRecRecalcMode::~QpRecRecalcMode()
362 {
363 }
364 
365 
366 void
mode(MODE pMode)367 QpRecRecalcMode::mode(MODE pMode)
368 {
369     cMode = pMode;
370 }
371 
372 QpRecRecalcMode::MODE
mode()373 QpRecRecalcMode::mode()
374 {
375     return cMode;
376 }
377 
378 
379 // -----------------------------------------------------------------------
380 
QpRecRecalcOrder(QP_INT16,QpIStream & pIn)381 QpRecRecalcOrder::QpRecRecalcOrder(QP_INT16, QpIStream& pIn)
382         : QpRec(QpRecalcOrder)
383 {
384     QP_INT8 lOrder;
385 
386     pIn >> lOrder;
387 
388     cOrder = (ORDER)(unsigned char) lOrder;
389 
390     QP_DEBUG("Recalc Order = "
391              << (int)lOrder << (cOrder == Natural ? " (Natural)"
392                                 : cOrder == Column ? " (Column)"
393                                 : cOrder == Row  ? " (Row)"
394                                 : " (Unknown)"
395                                )
396              << endl
397             );
398 }
399 
~QpRecRecalcOrder()400 QpRecRecalcOrder::~QpRecRecalcOrder()
401 {
402 }
403 
404 
405 void
order(ORDER pOrder)406 QpRecRecalcOrder::order(ORDER pOrder)
407 {
408     cOrder = pOrder;
409 }
410 
411 QpRecRecalcOrder::ORDER
order()412 QpRecRecalcOrder::order()
413 {
414     return cOrder;
415 }
416 
417 
418 // -----------------------------------------------------------------------
419 
QpRecEmptyCell(QP_INT16,QpIStream & pIn)420 QpRecEmptyCell::QpRecEmptyCell(QP_INT16, QpIStream& pIn)
421         : QpRecCell(QpEmptyCell)
422 {
423     QP_DEBUG("Empty Cell - ");
424 
425     loadCellInfo(pIn);
426 
427     QP_DEBUG(endl);
428 }
429 
~QpRecEmptyCell()430 QpRecEmptyCell::~QpRecEmptyCell()
431 {
432 }
433 
434 
435 // -----------------------------------------------------------------------
436 
QpRecIntegerCell(QP_INT16,QpIStream & pIn)437 QpRecIntegerCell::QpRecIntegerCell(QP_INT16, QpIStream& pIn)
438         : QpRecCell(QpIntegerCell)
439 {
440     QP_DEBUG("Integer Cell - ");
441 
442     loadCellInfo(pIn);
443 
444     pIn >> cInt;
445 
446     QP_DEBUG(", Int " << cInt << endl);
447 }
448 
~QpRecIntegerCell()449 QpRecIntegerCell::~QpRecIntegerCell()
450 {
451 }
452 
453 QP_INT16
integer()454 QpRecIntegerCell::integer()
455 {
456     return cInt;
457 }
458 
459 // -----------------------------------------------------------------------
460 
QpRecFloatingPointCell(QP_INT16,QpIStream & pIn)461 QpRecFloatingPointCell::QpRecFloatingPointCell(QP_INT16, QpIStream& pIn)
462         : QpRecCell(QpFloatingPointCell)
463 {
464     QP_DEBUG("Float Cell - ");
465 
466     loadCellInfo(pIn);
467 
468     pIn >> cValue;
469 
470     QP_DEBUG(", Value " << cValue << endl);
471 }
472 
~QpRecFloatingPointCell()473 QpRecFloatingPointCell::~QpRecFloatingPointCell()
474 {
475 }
476 
477 QP_INT64
value()478 QpRecFloatingPointCell::value()
479 {
480     return cValue;
481 }
482 
483 // -----------------------------------------------------------------------
484 
QpRecLabelCell(QP_INT16 pLen,QpIStream & pIn)485 QpRecLabelCell::QpRecLabelCell(QP_INT16 pLen, QpIStream& pIn)
486         : QpRecCell(QpLabelCell)
487 {
488     QP_DEBUG("Label Cell - ");
489     int lLabelLen = pLen - loadCellInfo(pIn) - 1;
490 
491     pIn >> cLabelPrefix;
492 
493     cLabel = new char[lLabelLen];
494 
495     pIn.read(cLabel, lLabelLen);
496 
497     QP_DEBUG(", Prefix " << cLabelPrefix << ", Label " << cLabel << endl);
498 }
499 
~QpRecLabelCell()500 QpRecLabelCell::~QpRecLabelCell()
501 {
502     delete [] cLabel;
503     cLabel =  0;
504 }
505 
506 char
labelPrefix()507 QpRecLabelCell::labelPrefix()
508 {
509     return cLabelPrefix;
510 }
511 
512 const char*
label()513 QpRecLabelCell::label()
514 {
515     return cLabel;
516 }
517 
518 // -----------------------------------------------------------------------
519 
QpRecFormulaCell(QP_INT16 pLen,QpIStream & pIn)520 QpRecFormulaCell::QpRecFormulaCell(QP_INT16 pLen, QpIStream& pIn)
521         : QpRecCell(QpFormulaCell)
522         , cFormula(0)
523 {
524     QP_DEBUG("Formula Cell - ");
525 
526     int lFormulaLen = pLen - loadCellInfo(pIn);
527 
528     pIn >> cLastValue;
529     lFormulaLen -= 8;
530 
531     pIn >> cState;
532     lFormulaLen -= 2;
533 
534     pIn >> cLen;
535     lFormulaLen -= 2;
536 
537     pIn >> cCellRef;
538     lFormulaLen -= 2;
539 
540     cFormula = new char[lFormulaLen];
541 
542     pIn.read(cFormula, lFormulaLen);
543 
544     QP_DEBUG(", LastValue " << cLastValue << ", State " << cState << endl);
545     QP_DEBUG("   FormulaLen " << cLen << ", CellRef " << cCellRef << ", Formula" << endl);
546 #ifdef QP_TRACE
547     Hexout(cFormula, lFormulaLen);
548 #endif
549     QP_DEBUG(endl);
550 }
551 
~QpRecFormulaCell()552 QpRecFormulaCell::~QpRecFormulaCell()
553 {
554     delete [] cFormula;
555     cFormula = 0;
556 }
557 
558 const char*
formula()559 QpRecFormulaCell::formula()
560 {
561     return cFormula;
562 }
563 
564 QP_INT16
formulaLen()565 QpRecFormulaCell::formulaLen()
566 {
567     return cLen;
568 }
569 
570 QP_INT16
formulaReferences()571 QpRecFormulaCell::formulaReferences()
572 {
573     return cCellRef;
574 }
575 
576 // -----------------------------------------------------------------------
577 
QpRecUnknown(QP_INT16,QP_INT16 pLen,QpIStream & pIn)578 QpRecUnknown::QpRecUnknown(QP_INT16 /*pType*/, QP_INT16 pLen, QpIStream& pIn)
579         : QpRec(QpUnknown)
580 {
581     QP_DEBUG("Unknown Type " << pType << ", len " << pLen << endl);
582 
583     if (pLen > 0) {
584         char* lBuf = new char[pLen];
585 
586         pIn.read(lBuf, pLen);
587 
588         delete [] lBuf;
589         lBuf = 0;
590     }
591 }
592 
~QpRecUnknown()593 QpRecUnknown::~QpRecUnknown()
594 {
595 }
596 
597 // -----------------------------------------------------------------------
598 
QpRecBop(QP_INT16,QpIStream & pIn)599 QpRecBop::QpRecBop(QP_INT16, QpIStream& pIn)
600         : QpRec(QpBop)
601 {
602     pIn >> cPageIndex;
603     QP_DEBUG("BOP: " << (unsigned)cPageIndex << endl);
604 }
605 
~QpRecBop()606 QpRecBop::~QpRecBop()
607 {
608 }
609 
610 
611 QP_UINT8
pageIndex()612 QpRecBop::pageIndex()
613 {
614     return cPageIndex;
615 }
616 
617 
618 // -----------------------------------------------------------------------
619 
QpRecPageName(QP_INT16,QpIStream & pIn)620 QpRecPageName::QpRecPageName(QP_INT16, QpIStream& pIn)
621         : QpRec(QpPageName)
622 {
623     pIn >> cPageName;
624 
625     QP_DEBUG("Page Name: " << cPageName << endl);
626 }
627 
~QpRecPageName()628 QpRecPageName::~QpRecPageName()
629 {
630     delete [] cPageName;
631 }
632 
633 const char*
pageName()634 QpRecPageName::pageName()
635 {
636     return cPageName;
637 }
638 // -----------------------------------------------------------------------
639 
QpRecPassword(QP_INT16 pLen,QpIStream & pIn)640 QpRecPassword::QpRecPassword(QP_INT16 pLen, QpIStream& pIn)
641         : QpRec(QpPassword)
642 {
643     QP_DEBUG("Password len = " << pLen << endl);
644 
645     cPassword = new QP_UINT8[pLen];
646 
647     pIn.read((char*)cPassword, pLen);
648 
649     QP_DEBUG("Password(Hex) = ");
650 #ifdef QP_TRACE
651     Hexout((char*)cPassword, pLen);
652 #endif
653     QP_DEBUG(endl);
654 }
655 
~QpRecPassword()656 QpRecPassword::~QpRecPassword()
657 {
658     delete [] cPassword;
659     cPassword = 0;
660 }
661 
662 const QP_UINT8*
password()663 QpRecPassword::password()
664 {
665     return cPassword;
666 }
667 
668