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