NumeRe v1.1.4
NumeRe: Framework für Numerische Rechnungen
file.cpp
Go to the documentation of this file.
1/*****************************************************************************
2 NumeRe: Framework fuer Numerische Rechnungen
3 Copyright (C) 2019 Erik Haenel et al.
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17******************************************************************************/
18
19#include <libsha.hpp>
20#include <libzygo.hpp>
21
22#include "file.hpp"
23#include "../datamanagement/tablecolumnimpl.hpp"
24#include "../IgorLib/ReadWave.h"
25#include "../utils/tools.hpp"
26#include "../utils/BasicExcel.hpp"
27#include "../utils/tinyxml2.h"
28#include "../ui/language.hpp"
29#include "../version.h"
30#include "../../kernel.hpp"
31
32#define DEFAULT_PRECISION 14
33
34extern Language _lang;
35
36namespace NumeRe
37{
38 using namespace std;
39
40 // This function determines the correct class to be used for the filename
41 // passed to this function. If there's no fitting file type, a null pointer
42 // is returned. The calling function is responsible for clearing the
43 // created instance. The returned pointer is of the type of GenericFile
44 // but references an instance of a derived class
45 GenericFile* getFileByType(const string& filename)
46 {
47 FileSystem _fSys;
49
50 // Get the extension of the filename
51 string sExt = toLowerCase(_fSys.getFileParts(filename).back());
52
53 // Create an instance of the selected file type
54 if (sExt == "ndat")
55 return new NumeReDataFile(filename);
56
57 if (sExt == "dat" && ZygoLib::DatFile::isDatFile(filename))
58 return new ZygoDat(filename);
59
60 if (sExt == "txt" || sExt == "dat" || !sExt.length())
61 return new TextDataFile(filename);
62
63 if (sExt == "csv")
64 return new CommaSeparatedValues(filename);
65
66 if (sExt == "tex")
67 return new LaTeXTable(filename);
68
69 if (sExt == "labx")
70 return new CassyLabx(filename);
71
72 if (sExt == "ibw")
73 return new IgorBinaryWave(filename);
74
75 if (sExt == "ods")
76 return new OpenDocumentSpreadSheet(filename);
77
78 if (sExt == "xls")
79 return new XLSSpreadSheet(filename);
80
81 if (sExt == "xlsx")
82 return new XLSXSpreadSheet(filename);
83
84 if (sExt == "jdx" || sExt == "dx" || sExt == "jcm")
85 return new JcampDX(filename);
86
87 // If no filetype matches, return a null pointer
88 return nullptr;
89 }
90
91
93 // class TextDataFile
95 //
96 TextDataFile::TextDataFile(const string& filename) : GenericFile(filename)
97 {
98 // Empty constructor
99 }
100
101
103 {
104 // Empty destructor
105 }
106
107
116 {
117 open(ios::in);
118
119 long long int nLine = 0;
120 long long int nComment = 0;
121
122 // Read the text file contents to memory
123 vector<string> vFileContents = readTextFile(true);
124
125 // Ensure that the file was not empty
126 if (!vFileContents.size())
128
129 // Replace tabulator characters with whitespaces but
130 // insert placeholders for empty table headlines
131 for (size_t i = 0; i < vFileContents.size(); i++)
132 {
133 if (!isNumeric(vFileContents[i]))
134 replaceTabSign(vFileContents[i], true);
135 else
136 {
137 replaceTabSign(vFileContents[i]);
138 stripTrailingSpaces(vFileContents[i]);
139 }
140 }
141
142 // Count the number of comment lines, which are found
143 // in the files contents.
144 for (size_t i = 0; i < vFileContents.size(); i++)
145 {
146 if (vFileContents[i][0] == '#')
147 nComment++;
148 }
149
150 // If no comments have been found, use all non-numeric lines
151 if (!nComment)
152 {
153 for (size_t i = 0; i < vFileContents.size(); i++)
154 {
155 if (!isNumeric(vFileContents[i]))
156 nComment++;
157 }
158 }
159
160 // If now all lines are comments, we have a string table
161 if (vFileContents.size() == nComment)
162 nComment = 1;
163
164 // Determine now, how many columns are found in the file
165 for (size_t i = 0; i < vFileContents.size(); i++)
166 {
167 size_t elem = tokenize(vFileContents[i], " ", true).size();
168
169 if (elem > nCols)
170 nCols = elem;
171 }
172
173 // Set the final dimensions
174 nRows = vFileContents.size() - nComment;
175
176 // Something's wrong here!
177 if (!nCols || !nRows)
179
180 // Create the target storage
182
183 for (TblColPtr& col : *fileData)
184 {
185 col.reset(new StringColumn);
186 }
187
188 nLine = 0;
189
190 // Copy the data from the file to the internal memory
191 for (size_t i = 0; i < vFileContents.size(); i++)
192 {
193 if (vFileContents[i][0] == '#' || (i < nComment && !isNumeric(vFileContents[i])))
194 {
195 // ignore table heads
196 continue;
197 }
198
199 // Tokenize the current line
200 vector<string> vLine = tokenize(vFileContents[i], " ", true);
201
202 // Ensure that the number of columns is matching
203 // If it does not match, then we did not determine
204 // the columns correctly
205 if (vLine.size() > nCols)
207
208 // Go through the already tokenized line and store
209 // the converted values
210 for (size_t j = 0; j < vLine.size(); j++)
211 {
212 replaceAll(vLine[j], "\1", " ");
213 fileData->at(j)->setValue(nLine, vLine[j]);
214 }
215
216 nLine++;
217 }
218
219 // Decode the table headlines in this member function
220 if (nComment)
221 {
222 decodeTableHeads(vFileContents, nComment);
223 }
224 }
225
226
235 {
236 // Open the file
237 open(ios::out | ios::trunc);
238
239 // Write the header
240 writeHeader();
241
242 // Get the necessary column widths and the number
243 // of lines, which are needed for the column heads
244 size_t nNumberOfHeadlines = 1u;
245 vector<size_t> vColumns = calculateColumnWidths(nNumberOfHeadlines);
246
247 // Write the column heads and append a separator
248 writeTableHeads(vColumns, nNumberOfHeadlines);
249 addSeparator(vColumns);
250
251 // Write the actual data
252 writeTableContents(vColumns);
253 }
254
255
264 {
265 string sBuild = AutoVersion::YEAR;
266 sBuild += "-";
267 sBuild += AutoVersion::MONTH;
268 sBuild += "-";
269 sBuild += AutoVersion::DATE;
270
271 fFileStream << "#\n";
272 fFileStream << "# " + _lang.get("OUTPUT_PRINTLEGAL_LINE1") << "\n";
273 fFileStream << "# NumeRe: Framework für Numerische Rechnungen" << "\n";
274 fFileStream << "#=============================================" << "\n";
275 fFileStream << "# " + _lang.get("OUTPUT_PRINTLEGAL_LINE2", sVersion, sBuild) << "\n";
276 fFileStream << "# " + _lang.get("OUTPUT_PRINTLEGAL_LINE3", sBuild.substr(0, 4)) << "\n";
277 fFileStream << "#\n";
278 fFileStream << "# " + _lang.get("OUTPUT_PRINTLEGAL_LINE4", getTimeStamp(false)) << "\n";
279 fFileStream << "#\n";
280 fFileStream << "# " + _lang.get("OUTPUT_PRINTLEGAL_STD") << "\n#" << endl;
281 }
282
283
293 void TextDataFile::writeTableHeads(const vector<size_t>& vColumnWidth, size_t nNumberOfLines)
294 {
295 for (size_t i = 0; i < nNumberOfLines; i++)
296 {
297 fFileStream << "# ";
298
299 for (long long int j = 0; j < nCols; j++)
300 {
301 fFileStream.width(vColumnWidth[j]);
302 fFileStream.fill(' ');
304
305 if (j+1 < nCols)
306 {
307 fFileStream.width(0);
308 fFileStream << " ";
309 }
310 }
311
312 fFileStream.width(0);
313 fFileStream << "\n";
314 }
315 }
316
317
326 void TextDataFile::writeTableContents(const vector<size_t>& vColumnWidth)
327 {
328 for (long long int i = 0; i < nRows; i++)
329 {
330 for (long long int j = 0; j < nCols; j++)
331 {
332 fFileStream.width(vColumnWidth[j]+2);
333 fFileStream.fill(' ');
334 fFileStream.precision(nPrecFields);
335
336 // Handle NaNs correctly
337 if (!fileData->at(j)->isValid(i))
338 fFileStream << "---";
339 else
340 {
341 if (fileData->at(j)->m_type == TableColumn::TYPE_VALUE)
342 fFileStream << toString(fileData->at(j)->getValue(i), nPrecFields);
343 else
344 fFileStream << fileData->at(j)->getValueAsInternalString(i);
345 }
346 }
347
348 fFileStream.width(0);
349 fFileStream << "\n";
350 }
351 }
352
353
362 void TextDataFile::addSeparator(const vector<size_t>& vColumnWidth)
363 {
364 fFileStream << "#=";
365
366 for (size_t j = 0; j < vColumnWidth.size(); j++)
367 {
368 fFileStream.width(vColumnWidth[j]);
369 fFileStream.fill('=');
370 fFileStream << "=";
371
372 if (j+1 < vColumnWidth.size())
373 fFileStream << "==";
374 }
375
376 fFileStream << "\n";
377 }
378
379
390 void TextDataFile::decodeTableHeads(vector<string>& vFileContents, long long int nComment)
391 {
392 long long int _nHeadline = 0;
393 string sCommentSign = "#";
394
395 // If the length of the file is larger than 14 lines, then
396 // append equal signs to the comment sign
397 if (vFileContents.size() > 14)
398 sCommentSign.append(vFileContents[13].length()-1, '=');
399
400 // This section will locate the first line in the comment section,
401 // where the table heads are located. Depending on the format of
402 // the comment section in the file, the following code tries
403 // different approaches
404 if (nComment >= 13 && vFileContents[2].substr(0, 21) == "# NumeRe: Framework f")
405 {
406 // This is a NumeRe-created text file
407 // Find the first actual headline
408 for (size_t k = 11; k < vFileContents.size(); k++)
409 {
410 // Is this the first separator line?
411 if (vFileContents[k] == sCommentSign)
412 {
413 // Now search for the last empty line right
414 // before the sepator line
415 for (int kk = k-1; kk >= 0; kk--)
416 {
417 if (vFileContents[kk] == "#")
418 {
419 _nHeadline = kk+2;
420 break;
421 }
422 }
423
424 break;
425 }
426 }
427 }
428 else if (nComment == 1)
429 {
430 // That's a custom created text file with only one possible
431 // candidate for the table heads
432 for (size_t i = 0; i < vFileContents.size(); i++)
433 {
434 if (vFileContents[i][0] == '#')
435 {
436 // Starting with a "#" sign
437 if (vFileContents[i].find(' ') != string::npos)
438 {
439 // Insert a whitespace character right after
440 // the comment character to make it separatable
441 // using the tokenizer
442 if (vFileContents[i][1] != ' ')
443 {
444 for (unsigned int n = 0; n < vFileContents[i].length(); n++)
445 {
446 if (vFileContents[i][n] != '#')
447 {
448 if (vFileContents[i][n] != ' ')
449 vFileContents[i].insert(n, " ");
450
451 break;
452 }
453 }
454 }
455
456 // Considering the comment character, which is the
457 // first token, does the number of elements match to
458 // the number of columns?
459 if (nCols + 1 == tokenize(vFileContents[i], " ", true).size())
460 _nHeadline = 1;
461 }
462
463 break;
464 }
465 else if (!isNumeric(vFileContents[i]))
466 {
467 // Simply a non-numeric line
468 if (nCols == tokenize(vFileContents[i], " ", true).size())
469 _nHeadline = 1;
470 }
471 }
472 }
473 else if (vFileContents[0][0] == '#' || !isNumeric(vFileContents[0]))
474 {
475 // This is the most generic approach: every line, which contains
476 // non-numeric characters is examined to locate the correct line
477 // containing the table column heads
478 for (size_t i = 0; i < vFileContents.size(); i++)
479 {
480 if (vFileContents[i][0] != '#' && isNumeric(vFileContents[i]))
481 {
482 if (vFileContents[i-1][0] == '#')
483 {
484 if ((nCols > 1 && vFileContents[i-1].find(' ') != string::npos)
485 || (nCols == 1 && vFileContents[i-1].length() > 1))
486 {
487 // Insert a whitespace character right after
488 // the comment character to make it separatable
489 // using the tokenizer
490 if (vFileContents[i-1][1] != ' ')
491 {
492 for (unsigned int n = 0; n < vFileContents[i-1].length(); n++)
493 {
494 if (vFileContents[i-1][n] != '#')
495 {
496 if (vFileContents[i-1][n] != ' ')
497 vFileContents[i-1].insert(n, " ");
498
499 break;
500 }
501 }
502 }
503
504 // Considering the comment character, which is the
505 // first token, does the number of elements match to
506 // the number of columns?
507 if (tokenize(vFileContents[i-1], " ", true).size() <= nCols+1)
508 {
509 _nHeadline = i;
510 break;
511 }
512 }
513
514 if (i > 1
515 && vFileContents[i-2][0] == '#'
516 && ((vFileContents[i-2].find(' ') != string::npos && nCols > 1)
517 || (nCols == 1 && vFileContents[i-2].length() > 1)))
518 {
519 // Insert a whitespace character right after
520 // the comment character to make it separatable
521 // using the tokenizer
522 if (vFileContents[i-2][1] != ' ')
523 {
524 for (size_t n = 0; n < vFileContents[i-2].length(); n++)
525 {
526 if (vFileContents[i-2][n] != '#')
527 {
528 if (vFileContents[i-2][n] != ' ')
529 vFileContents[i-2].insert(n, " ");
530
531 break;
532 }
533 }
534 }
535
536 // Considering the comment character, which is the
537 // first token, does the number of elements match to
538 // the number of columns?
539 if (tokenize(vFileContents[i-2], " ", true).size() <= nCols+1)
540 _nHeadline = i-1;
541 }
542 }
543 else if (!isNumeric(vFileContents[i-1]))
544 {
545 if ((vFileContents[i-1].find(' ') != string::npos && nCols > 1)
546 || (nCols == 1 && vFileContents[i-1].length() > 1))
547 {
548 // Insert a whitespace character right after
549 // the comment character to make it separatable
550 // using the tokenizer
551 if (vFileContents[i-1][1] != ' ')
552 {
553 for (size_t n = 0; n < vFileContents[i-1].length(); n++)
554 {
555 if (vFileContents[i-1][n] != '#')
556 {
557 if (vFileContents[i-1][n] != ' ')
558 vFileContents[i-1].insert(n, " ");
559
560 break;
561 }
562 }
563 }
564
565 // Considering the comment character, which is the
566 // first token, does the number of elements match to
567 // the number of columns?
568 if (tokenize(vFileContents[i-1], " ", true).size() == nCols+1)
569 {
570 _nHeadline = i;
571 break;
572 }
573 }
574
575 if (i > 1
576 && vFileContents[i-2][0] == '#'
577 && ((vFileContents[i-2].find(' ') != string::npos && nCols > 1)
578 || (nCols == 1 && vFileContents[i-2].length() > 1)))
579 {
580 // Insert a whitespace character right after
581 // the comment character to make it separatable
582 // using the tokenizer
583 if (vFileContents[i-2][1] != ' ')
584 {
585 for (unsigned int n = 0; n < vFileContents[i-2].length(); n++)
586 {
587 if (vFileContents[i-2][n] != '#')
588 {
589 if (vFileContents[i-2][n] != ' ')
590 vFileContents[i-2].insert(n, " ");
591
592 break;
593 }
594 }
595 }
596
597 // Considering the comment character, which is the
598 // first token, does the number of elements match to
599 // the number of columns?
600 if (tokenize(vFileContents[i-2], " ", true).size() == nCols+1)
601 _nHeadline = i-1;
602 }
603 }
604
605 break;
606 }
607 }
608 }
609
610 // This section will extract the identified table
611 // column heads and store them in the internal
612 // storage
613 if (_nHeadline)
614 {
615 long long int n = 0;
616
617 // Go through the contents of the whole file and
618 // search for the non-numeric lines in the file
619 for (size_t i = 0; i < vFileContents.size(); i++)
620 {
621 // Is this a non-numeric line?
622 if (vFileContents[i][0] == '#' || !isNumeric(vFileContents[i]))
623 {
624 // increment the counter variable first,
625 // because we counted from 1 previously
626 n++;
627
628 // Does the counter match the selected
629 // headline?
630 if (n == _nHeadline)
631 {
632 // This section creates the needed "empty" tokens,
633 // which will be used to determine the association
634 // of single strings (i.e. a single string in the
635 // second line of a column head)
636 for (size_t k = i+1; k < vFileContents.size(); k++)
637 {
638 // If the current line contains the placeholders,
639 // which we introduced before, we abort at this
640 // line, because we already know the number of
641 // tokens in this line
642 if (vFileContents[k].find(" _ ") != string::npos
643 || (vFileContents[k].find_first_not_of(" #") != string::npos && vFileContents[k][vFileContents[k].find_first_not_of(" #")] == '_')
644 || vFileContents[k].back() == '_')
645 {
646 break;
647 }
648
649 // Abort on non-numeric lines
650 if (vFileContents[k][0] != '#' && isNumeric(vFileContents[k]))
651 break;
652
653 // Abort on separator lines
654 if (vFileContents[k].substr(0, 4) == "#===" || vFileContents[k].substr(0, 5) == "# ===")
655 break;
656
657 // Ensure that the current line has the same length
658 // as the first line in the current headline set. Also,
659 // transform multiple whitespaces into underscores, to mirror
660 // the "tokens" from the previous lines
661 if (vFileContents[k].length() == vFileContents[i].length())
662 {
663 // Mirror the tokens from the previous lines
664 for (unsigned int l = 0; l < vFileContents[k].length(); l++)
665 {
666 if (vFileContents[i][l] != ' ' && vFileContents[k][l] == ' ')
667 vFileContents[k][l] = '_';
668 }
669 }
670 else if (vFileContents[k].length() < vFileContents[i].length() && vFileContents[i].back() != ' ' && vFileContents[k].back() != ' ')
671 {
672 vFileContents[k].append(vFileContents[i].length() - vFileContents[k].length(), ' ');
673
674 // Mirror the tokens from the previous lines
675 for (unsigned int l = 0; l < vFileContents[k].length(); l++)
676 {
677 if (vFileContents[i][l] != ' ' && vFileContents[k][l] == ' ')
678 vFileContents[k][l] = '_';
679 }
680 }
681 else if (vFileContents[k].length() > vFileContents[i].length() && vFileContents[k].back() != ' ' && vFileContents[i].back() != ' ')
682 {
683 // Mirror the tokens from the previous lines
684 for (unsigned int l = 0; l < vFileContents[i].length(); l++)
685 {
686 if (vFileContents[i][l] != ' ' && vFileContents[k][l] == ' ')
687 vFileContents[k][l] = '_';
688 }
689 }
690 else
691 break;
692 }
693
694 bool bBreakSignal = false;
695 vector<string> vHeadline;
696 vHeadline.resize((unsigned int)(2*nCols), "");
697
698 // Go now through the selected headlines and
699 // break them down into the single columns. Based
700 // upon the created tokens from the previous code
701 // section, we can ensure that we may keep the
702 // association of the different lines
703 for (size_t k = i; k < vFileContents.size(); k++)
704 {
705 // Abort on numeric lines
706 if ((vFileContents[k][0] != '#' && isNumeric(vFileContents[k])) || i+nComment == k)
707 break;
708
709 // Abort on separator lines
710 if (vFileContents[k].substr(0, 4) == "#===" || vFileContents[k].substr(0, 5) == "# ===")
711 break;
712
713 // Tokenize the current line
714 vector<string> vLine = tokenize(vFileContents[k], " ", true);
715
716 // Remove the comment character from the list
717 // of tokens
718 if (vLine.front() == "#")
719 vLine.erase(vLine.begin());
720
721 // Distribute the tokens into the single column
722 // headings and insert line break characters
723 // whereever needed. Of course, we will ignore
724 // the inserted placeholders in this case
725 for (size_t j = 0; j < vLine.size(); j++)
726 {
727 if (k == i)
728 vHeadline.push_back("");
729
730 if (k != i && j >= vHeadline.size())
731 {
732 bBreakSignal = true;
733 break;
734 }
735
736 // Ignore placeholder tokens
737 if (vLine[j].find_first_not_of('_') == string::npos)
738 continue;
739
740 // Strip all underscores from the
741 // current token
742 while (vLine[j].front() == '_')
743 vLine[j].erase(0,1);
744
745 while (vLine[j].back() == '_')
746 vLine[j].pop_back();
747
748 replaceAll(vLine[j], "\1", " ");
749
750 // Append the current token to the
751 // corresponding column heading and
752 // insert the linebreak character,
753 // if needed
754 if (!vHeadline[j].length())
755 vHeadline[j] = utf8parser(vLine[j]);
756 else
757 {
758 vHeadline[j] += "\n";
759 vHeadline[j] += utf8parser(vLine[j]);
760 }
761 }
762
763 if (bBreakSignal)
764 break;
765 }
766
767 // Copy the decoded column headings to
768 // the internal memory
769 for (size_t col = 0; col < std::min(vHeadline.size(), (size_t)nCols); col++)
770 {
771 if (!fileData->at(col))
772 fileData->at(col).reset(new StringColumn);
773
774 fileData->at(col)->m_sHeadLine = vHeadline[col];
775 }
776
777 // Return here
778 return;
779 }
780 }
781 }
782 }
783 }
784
785
795 vector<size_t> TextDataFile::calculateColumnWidths(size_t& nNumberOfLines)
796 {
797 vector<size_t> vColumnWidths;
798 const size_t NUMBERFIELDLENGTH = nPrecFields + 7;
799
800 // Go through the column heads in memory, determine
801 // their cell extents and store the maximal value of
802 // the extents and the needed width for the numerical
803 // value
804 for (long long int j = 0; j < nCols; j++)
805 {
806 if (!fileData->at(j))
807 {
808 vColumnWidths.push_back(TableColumn::getDefaultColumnHead(j).length());
809 continue;
810 }
811
812 pair<size_t, size_t> pCellExtents = calculateCellExtents(fileData->at(j)->m_sHeadLine);
813 vColumnWidths.push_back(max(NUMBERFIELDLENGTH, pCellExtents.first));
814
815 if (nNumberOfLines < pCellExtents.second)
816 nNumberOfLines = pCellExtents.second;
817 }
818
819 return vColumnWidths;
820 }
821
822
824 // class NumeReDataFile
826 //
827 NumeReDataFile::NumeReDataFile(const string& filename)
828 : GenericFile(filename),
829 isLegacy(false), timeStamp(0), versionMajor(0), versionMinor(0),
830 versionBuild(0), fileVersionRead(1.0f)
831 {
832 // Empty constructor
833 }
834
835
844 {
845 isLegacy = file.isLegacy;
846 timeStamp = file.timeStamp;
847 sComment = file.sComment;
852 }
853
854
856 {
857 // Empty destructor
858 }
859
860
872 {
876 writeNumField(time(0));
877
879
882 checkPos = tellp();
883 writeStringField("SHA-256:" + sha256(""));
884 writeNumField<size_t>(10);
885 checkStart = tellp();
888
889 // The following fields are placeholders
890 // for further changes. They may be filled
891 // in future versions and will be ignored
892 // in older versions of NumeRe
893 writeStringField("FTYPE=LLINT");
894 long long int t = _time64(0);
895 writeNumBlock<long long int>(&t, 1);
896 writeStringField("FTYPE=DOUBLE");
897 writeNumBlock<double>(nullptr, 0);
898 writeStringField("FTYPE=DOUBLE");
899 writeNumBlock<double>(nullptr, 0);
900 writeStringField("FTYPE=DOUBLE");
901 writeNumBlock<double>(nullptr, 0);
902
903 // Finally, write the dimensions of the
904 // target data
907 }
908
909
921 {
922 writeNumField(1LL);
923 writeNumField(1LL);
924 writeStringField("THIS_FILE_NEEDS_AT_LEAST_VERSION_v1.1.5 ");
925 long long int appZeros = 0;
926 double data = 1.15;
927 bool valid = true;
928 fFileStream.write((char*)&appZeros, sizeof(long long int));
929 fFileStream.write((char*)&data, sizeof(double));
930 fFileStream.write((char*)&valid, sizeof(bool));
931 }
932
933
943 {
944 // Open the file in binary mode and truncate
945 // its contents (this will only be done, if
946 // it's not already open, because otherwise
947 // the cache file would be overwritten by each
948 // table in memory completely)
949 if (!is_open())
950 open(ios::binary | ios::in | ios::out | ios::trunc);
951
952 // Write the file header
953 writeHeader();
954
955 // Write the columns
956 for (TblColPtr& col : *fileData)
957 writeColumn(col);
958
959 size_t posEnd = tellp();
960
962 std::string checkSum = sha256(fFileStream, checkStart, posEnd-checkStart);
963
964 // Update the checksum and file end
966 writeStringField("SHA-256:" + checkSum);
967 writeNumField<size_t>(posEnd);
968
969 // Go back to the end
970 seekp(posEnd);
971 }
972
973
982 {
983 if (!col)
984 {
986 writeStringField("DTYPE=NONE");
987 return;
988 }
989
990 writeStringField(col->m_sHeadLine);
991
992 if (col->m_type == TableColumn::TYPE_VALUE
993 || col->m_type == TableColumn::TYPE_DATETIME
994 || col->m_type == TableColumn::TYPE_LOGICAL)
995 {
996 // All these colums write complex values
997 writeStringField("DTYPE=COMPLEX");
998
999 // Note the type of the column
1000 if (col->m_type == TableColumn::TYPE_VALUE)
1001 writeStringField("CTYPE=VALUE");
1002 else if (col->m_type == TableColumn::TYPE_DATETIME)
1003 writeStringField("CTYPE=DATETIME");
1004 else if (col->m_type == TableColumn::TYPE_LOGICAL)
1005 writeStringField("CTYPE=LOGICAL");
1006
1007 size_t lenPos = tellp();
1008 // Store the position of the next column
1009 writeNumField<size_t>(lenPos);
1010
1011 std::vector<mu::value_type> values = col->getValue(VectorIndex(0, VectorIndex::OPEN_END));
1012 writeNumBlock<mu::value_type>(&values[0], values.size());
1013
1014 size_t endPos = tellp();
1015 seekp(lenPos);
1016 writeNumField<size_t>(endPos-lenPos);
1017 seekp(endPos);
1018 }
1019 else if (col->m_type == TableColumn::TYPE_STRING
1020 || col->m_type == TableColumn::TYPE_CATEGORICAL)
1021 {
1022 // All these colums write strings as values
1023 writeStringField("DTYPE=STRING");
1024
1025 // Note the type of the column
1026 if (col->m_type == TableColumn::TYPE_STRING)
1027 writeStringField("CTYPE=STRING");
1028 else if (col->m_type == TableColumn::TYPE_CATEGORICAL)
1029 writeStringField("CTYPE=CATEGORICAL");
1030
1031 size_t lenPos = tellp();
1032 // Store the position of the next column
1033 writeNumField<size_t>(lenPos);
1034
1035 std::vector<std::string> values = col->getValueAsInternalString(VectorIndex(0, VectorIndex::OPEN_END));
1036 writeStringBlock(&values[0], values.size());
1037
1038 size_t endPos = tellp();
1039 seekp(lenPos);
1040 writeNumField<size_t>(endPos-lenPos);
1041 seekp(endPos);
1042 }
1043 else if (col->m_type == TableColumn::TYPE_NONE)
1044 {
1045 writeStringField("DTYPE=NONE");
1046 }
1047 }
1048
1049
1061 {
1062 // Read the basic information
1063 versionMajor = readNumField<long int>();
1064 versionMinor = readNumField<long int>();
1065 versionBuild = readNumField<long int>();
1066 time_t oldTime = readNumField<time_t>();
1067
1068 // Detect, whether this file was created in
1069 // legacy format (earlier than v1.1.2)
1070 if (versionMajor * 100 + versionMinor * 10 + versionBuild <= 111)
1071 {
1072 isLegacy = true;
1073 fileVersionRead = 1.0f;
1074 nRows = readNumField<long long int>();
1075 nCols = readNumField<long long int>();
1076 timeStamp = oldTime;
1077 return;
1078 }
1079
1080 // Omitt the dummy header
1082
1083 // Read the file version number (which is
1084 // independent on the version number of
1085 // NumeRe)
1086 short fileVerMajor = readNumField<short>();
1087 short fileVerMinor = readNumField<short>();
1088 fileVersionRead = fileVerMajor + fileVerMinor / 100.0;
1089
1090 // Ensure that the major version of the file
1091 // is not larger than the major version
1092 // implemented in this class (minor version
1093 // changes shall be downwards compatible)
1094 if (fileVerMajor > fileSpecVersionMajor)
1096
1097 // Read checksum
1098 if (fileVersionRead >= 4.0)
1099 {
1100 std::string sha_check = readStringField();
1101 size_t fileEnd = readNumField<size_t>();
1102
1103 size_t checkStart = tellg();
1104
1105 std::string sha = "SHA-256:" + sha256(fFileStream, checkStart, fileEnd-checkStart);
1106
1107 // Is it corrupted?
1108 if (sha_check != sha)
1109 NumeReKernel::issueWarning(_lang.get("COMMON_DATAFILE_CORRUPTED", sFileName));
1110
1112 }
1113
1114 // Read the table name and the comment
1117
1118 // Read now the three empty fields of the
1119 // header. We created special functions for
1120 // reading and deleting arbitary data types
1121 long long int size;
1122 string type;
1123 void* data = readGenericField(type, size);
1124
1125 // Version 2.1 introduces 64 bit time stamps
1126 if (fileVersionRead >= 2.01 && type == "LLINT" && size == 1u)
1127 timeStamp = *(long long int*)data;
1128 else
1129 timeStamp = oldTime;
1130
1131 deleteGenericData(data, type);
1132
1133 data = readGenericField(type, size);
1134 deleteGenericData(data, type);
1135
1136 data = readGenericField(type, size);
1137 deleteGenericData(data, type);
1138
1139 // Version 3.0 introduces another generic field
1140 if (fileVersionRead >= 3.00)
1141 {
1142 data = readGenericField(type, size);
1143 deleteGenericData(data, type);
1144 }
1145 else
1146 {
1147 // Determine the data type of the table
1148 string dataType = readStringField();
1149
1150 // Ensure that the data type is DOUBLE
1151 if (dataType != "DTYPE=DOUBLE")
1153 }
1154
1155 // Read the dimensions of the table
1156 nRows = readNumField<long long int>();
1157 nCols = readNumField<long long int>();
1158 }
1159
1160
1170 {
1171 readNumField<long long int>();
1172 readNumField<long long int>();
1174 long long int appZeros = 0;
1175 double data = NAN;
1176 bool valid = false;
1177 fFileStream.read((char*)&appZeros, sizeof(long long int));
1178 fFileStream.read((char*)&data, sizeof(double));
1179 fFileStream.read((char*)&valid, sizeof(bool));
1180 }
1181
1182
1191 {
1192 // Open the file in binary mode, if it's not
1193 // already open
1194 if (!is_open())
1195 open(ios::binary | ios::in);
1196
1197 // Read the file header and determine,
1198 // whether the file is in legacy mode
1199 readHeader();
1200
1201 // If the file is in legacy mode, read
1202 // the remaining file in legacy mode as
1203 // well
1204 if (isLegacy)
1205 {
1207 return;
1208 }
1209
1210 // Create empty storage
1211 createStorage();
1212
1213 // Version 3.0 introduces column-like layout and v4.0 added
1214 // more columns and improved backwards compatibility
1215 if (fileVersionRead >= 4.00)
1216 {
1217 if (fileData)
1218 {
1219 for (TblColPtr& col : *fileData)
1220 {
1221 readColumnV4(col);
1222 }
1223 }
1224
1225 return;
1226 }
1227 else if (fileVersionRead >= 3.00)
1228 {
1229 if (fileData)
1230 {
1231 for (TblColPtr& col : *fileData)
1232 {
1233 readColumn(col);
1234 }
1235 }
1236
1237 return;
1238 }
1239
1240 long long int stringBlockSize;
1241 long long int dataarrayrows;
1242 long long int dataarraycols;
1243
1244 // Read the table column headers and the
1245 // table data and copy it to a ValueColumn
1246 // array
1247 std::string* sHeads = readStringBlock(stringBlockSize);
1248 double** data = readDataArray<double>(dataarrayrows, dataarraycols);
1249
1250 for (long long int j = 0; j < dataarraycols; j++)
1251 {
1252 fileData->at(j).reset(new ValueColumn);
1253 fileData->at(j)->m_sHeadLine = sHeads[j];
1254
1255 for (long long int i = 0; i < dataarrayrows; i++)
1256 {
1257 fileData->at(j)->setValue(i, data[i][j]);
1258 }
1259 }
1260
1261 // Free up memory
1262 delete[] sHeads;
1263
1264 for (long long int i = 0; i < dataarrayrows; i++)
1265 delete[] data[i];
1266
1267 delete[] data;
1268 }
1269
1270
1279 {
1280 std::string sHeadLine = readStringField();
1281 std::string sDataType = readStringField();
1282
1283 if (sDataType == "DTYPE=NONE")
1284 return;
1285
1286 if (sDataType == "DTYPE=COMPLEX")
1287 {
1288 col.reset(new ValueColumn);
1289 col->m_sHeadLine = sHeadLine;
1290 long long int size = 0;
1291 mu::value_type* values = readNumBlock<mu::value_type>(size);
1292 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<mu::value_type>(values, values+size));
1293 delete[] values;
1294 }
1295 else if (sDataType == "DTYPE=LOGICAL")
1296 {
1297 col.reset(new LogicalColumn);
1298 col->m_sHeadLine = sHeadLine;
1299 long long int size = 0;
1300 mu::value_type* values = readNumBlock<mu::value_type>(size);
1301 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<mu::value_type>(values, values+size));
1302 delete[] values;
1303 }
1304 else if (sDataType == "DTYPE=DATETIME")
1305 {
1306 col.reset(new DateTimeColumn);
1307 col->m_sHeadLine = sHeadLine;
1308 long long int size = 0;
1309 mu::value_type* values = readNumBlock<mu::value_type>(size);
1310 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<mu::value_type>(values, values+size));
1311 delete[] values;
1312 }
1313 else if (sDataType == "DTYPE=STRING")
1314 {
1315 col.reset(new StringColumn);
1316 col->m_sHeadLine = sHeadLine;
1317 long long int size = 0;
1318 std::string* strings = readStringBlock(size);
1319 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<std::string>(strings, strings+size));
1320 delete[] strings;
1321 }
1322 else if (sDataType == "DTYPE=CATEGORICAL")
1323 {
1324 col.reset(new CategoricalColumn);
1325 col->m_sHeadLine = sHeadLine;
1326 long long int size = 0;
1327 std::string* strings = readStringBlock(size);
1328 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<std::string>(strings, strings+size));
1329 delete[] strings;
1330 }
1331 }
1332
1333
1343 {
1344 std::string sHeadLine = readStringField();
1345 std::string sDataType = readStringField();
1346
1347 if (sDataType == "DTYPE=NONE")
1348 return;
1349
1350 if (sDataType == "DTYPE=COMPLEX")
1351 {
1352 // Get the actual column type
1353 std::string sColType = readStringField();
1354
1355 // Jump over the colum end information
1356 readNumField<size_t>();
1357
1358 // Create the column for the corresponding CTYPE
1359 if (sColType == "CTYPE=VALUE")
1360 col.reset(new ValueColumn);
1361 else if (sColType == "CTYPE=DATETIME")
1362 col.reset(new DateTimeColumn);
1363 else if (sColType == "CTYPE=LOGICAL")
1364 col.reset(new LogicalColumn);
1365 else // All others fall back to a generic value column
1366 col.reset(new ValueColumn);
1367
1368 col->m_sHeadLine = sHeadLine;
1369 long long int size = 0;
1370 mu::value_type* values = readNumBlock<mu::value_type>(size);
1371 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<mu::value_type>(values, values+size));
1372 delete[] values;
1373 }
1374 else if (sDataType == "DTYPE=STRING")
1375 {
1376 // Get the actual column type
1377 std::string sColType = readStringField();
1378
1379 // Jump over the colum end information
1380 readNumField<size_t>();
1381
1382 // Create the column for the corresponding CTYPE
1383 if (sColType == "CTYPE=STRING")
1384 col.reset(new StringColumn);
1385 else if (sColType == "CTYPE=CATEGORICAL")
1386 col.reset(new CategoricalColumn);
1387 else // All others fall back to a generic string column
1388 col.reset(new StringColumn);
1389
1390 col->m_sHeadLine = sHeadLine;
1391 long long int size = 0;
1392 std::string* strings = readStringBlock(size);
1393 col->setValue(VectorIndex(0, VectorIndex::OPEN_END), std::vector<std::string>(strings, strings+size));
1394 delete[] strings;
1395 }
1396 else
1397 {
1398 // In all other cases: just jump over this column
1399 seekg(readNumField<size_t>());
1400 }
1401 }
1402
1403
1414 {
1415 // Prepare some POD arrays to read the
1416 // blocks to memory
1417 size_t nLength = 0;
1418 bool* bValidEntry = new bool[nCols];
1419 char** cHeadLine = new char*[nCols];
1420 long long int* nAppendedZeros = new long long int[nCols];
1421
1422 // Create the internal storage
1423 createStorage();
1424
1425 // Read the table heads to the internal
1426 // storage
1427 for (long long int i = 0; i < nCols; i++)
1428 {
1429 fileData->at(i).reset(new ValueColumn);
1430
1431 nLength = 0;
1432 fFileStream.read((char*)&nLength, sizeof(size_t));
1433 cHeadLine[i] = new char[nLength];
1434 fFileStream.read(cHeadLine[i], sizeof(char)*nLength);
1435 fileData->at(i)->m_sHeadLine.resize(nLength-1);
1436
1437 for (unsigned int j = 0; j < nLength-1; j++)
1438 {
1439 fileData->at(i)->m_sHeadLine[j] = cHeadLine[i][j];
1440 }
1441 }
1442
1443 // Read the appended zeros field, which
1444 // is ignored in this implementation,
1445 // because the calling data object will
1446 // determine this information by itself
1447 fFileStream.read((char*)nAppendedZeros, sizeof(long long int)*nCols);
1448
1449 // Read the table data linewise to the
1450 // internal memory. We cannot read the
1451 // whole block at once, because the
1452 // two dimensional array is probably
1453 // not layed out as continous block
1454 // in memory
1455 double* data = new double[nCols];
1456
1457 for (long long int i = 0; i < nRows; i++)
1458 {
1459 fFileStream.read((char*)data, sizeof(double)*nCols);
1460
1461 for (long long int j = 0; j < nCols; j++)
1462 {
1463 fileData->at(j)->setValue(i, data[j]);
1464 }
1465 }
1466
1467 delete[] data;
1468
1469 // Read the validation block and apply
1470 // the contained information on the data
1471 // in the internal storage
1472 for (long long int i = 0; i < nRows; i++)
1473 {
1474 fFileStream.read((char*)bValidEntry, sizeof(bool)*nCols);
1475 for (long long int j = 0; j < nCols; j++)
1476 {
1477 if (!bValidEntry[j])
1478 fileData->at(j)->setValue(i, NAN);
1479 }
1480 }
1481
1482 // Free the created memory
1483 for (long long int i = 0; i < nCols; i++)
1484 delete[] cHeadLine[i];
1485
1486 delete[] cHeadLine;
1487 delete[] bValidEntry;
1488 delete[] nAppendedZeros;
1489 }
1490
1491
1503 void* NumeReDataFile::readGenericField(std::string& type, long long int& size)
1504 {
1505 // Determine the field data type
1506 type = readStringField();
1507 type.erase(0, type.find('=')+1);
1508 size = 0;
1509
1510 // Read the data block depending on the
1511 // data type and convert the pointer to
1512 // a void*
1513 if (type == "DOUBLE")
1514 {
1515 double* data = readNumBlock<double>(size);
1516 return (void*)data;
1517 }
1518 else if (type == "INT")
1519 {
1520 int* data = readNumBlock<int>(size);
1521 return (void*)data;
1522 }
1523 else if (type == "LINT")
1524 {
1525 long int* data = readNumBlock<long int>(size);
1526 return (void*)data;
1527 }
1528 else if (type == "LLINT")
1529 {
1530 long long int* data = readNumBlock<long long int>(size);
1531 return (void*)data;
1532 }
1533 else if (type == "UINT")
1534 {
1535 size_t* data = readNumBlock<size_t>(size);
1536 return (void*)data;
1537 }
1538 else if (type == "BYTE")
1539 {
1540 char* data = readNumBlock<char>(size);
1541 return (void*)data;
1542 }
1543 else if (type == "STRING")
1544 {
1545 string* data = readStringBlock(size);
1546 return (void*)data;
1547 }
1548
1549 return nullptr;
1550 }
1551
1552
1566 void NumeReDataFile::deleteGenericData(void* data, const string& type)
1567 {
1568 if (data)
1569 {
1570 if (type == "DOUBLE")
1571 delete[] (double*)data;
1572 else if (type == "INT")
1573 delete[] (int*)data;
1574 else if (type == "LINT")
1575 delete[] (long int*)data;
1576 else if (type == "LLINT")
1577 delete[] (long long int*)data;
1578 else if (type == "UINT")
1579 delete[] (size_t*)data;
1580 else if (type == "BYTE")
1581 delete[] (char*)data;
1582 else if (type == "STRING")
1583 delete[] (string*)data;
1584 }
1585 }
1586
1587
1599 {
1600 assign(file);
1601 isLegacy = file.isLegacy;
1602 timeStamp = file.timeStamp;
1603 sComment = file.sComment;
1607
1608 return *this;
1609 }
1610
1611
1621 {
1622 return toString((int)versionMajor) + "." + toString((int)versionMinor) + "." + toString((int)versionBuild);
1623 }
1624
1625
1627 // class CacheFile
1629 //
1630 CacheFile::CacheFile(const string& filename) : NumeReDataFile(filename), nIndexPos(0u)
1631 {
1632 // Empty constructor
1633 }
1634
1635
1642 {
1643
1644 if (nIndexPos && vFileIndex.size())
1645 {
1647 writeNumBlock(&vFileIndex[0], vFileIndex.size());
1648 }
1649 }
1650
1651
1662 {
1663 sComment.clear();
1664 sTableName.clear();
1665 clearStorage();
1666 }
1667
1668
1680 {
1681 reset();
1682 size_t pos = tellg();
1683
1684 if (std::find(vFileIndex.begin(), vFileIndex.end(), pos) == vFileIndex.end())
1685 throw SyntaxError(SyntaxError::CANNOT_READ_FILE, "numere.cache", "numere.cache");
1686
1687 if (vFileIndex.size() && !fFileStream.eof())
1688 readFile();
1689 }
1690
1691
1705 {
1706 if (vFileIndex.size())
1707 {
1708 // Store the current position in the
1709 // file in the file index array
1710 for (size_t i = 0; i < vFileIndex.size(); i++)
1711 {
1712 if (!vFileIndex[i])
1713 {
1714 vFileIndex[i] = tellp();
1715 break;
1716 }
1717 }
1718
1719 writeFile();
1720 }
1721 }
1722
1723
1733 {
1734 // Open the file in binary mode
1735 open(ios::binary | ios::in);
1736
1737 // Read the basic information
1738 versionMajor = readNumField<long int>();
1739 versionMinor = readNumField<long int>();
1740 versionBuild = readNumField<long int>();
1741 timeStamp = readNumField<time_t>();
1742
1743 // Ensure that this file contains
1744 // the "NUMERECACHEFILE" string
1745 if (readStringField() != "NUMERECACHEFILE")
1747
1748 // Read the file version information
1749 short fileVerMajor = readNumField<short>();
1750 readNumField<short>();
1751
1752 // Ensure that the file major version is
1753 // not larger than the one currently
1754 // implemented in this class
1755 if (fileVerMajor > fileSpecVersionMajor)
1757
1758 // Read the number of available tables
1759 // in the cache file
1760 size_t nNumberOfTables = readNumField<size_t>();
1761
1762 // Create the file index array. This array
1763 // may be used to support memory paging
1764 // in a future version of NumeRe
1765 vFileIndex = vector<size_t>(nNumberOfTables, 0u);
1766
1767 // Read the file index information in
1768 // the file to the newly created file
1769 // index array
1770 long long int size = 0;
1771 size_t* nIndex = readNumBlock<size_t>(size);
1772 copyArray(nIndex, &vFileIndex[0], nNumberOfTables);
1773 delete[] nIndex;
1774 }
1775
1776
1785 {
1786 // Open the file in binary mode and truncate
1787 // all its contents
1788 open(ios::binary | ios::in | ios::out | ios::trunc);
1789
1793 writeNumField(time(0));
1794 writeStringField("NUMERECACHEFILE");
1797
1798 // Write the length of the file index array
1799 writeNumField(vFileIndex.size());
1800
1801 // Store the current position in the file
1802 // to update the array in the future (done
1803 // in the destructor)
1804 nIndexPos = tellp();
1805
1806 // Write the file index to the file
1807 writeNumBlock(&vFileIndex[0], vFileIndex.size());
1808 }
1809
1810
1812 // class CassyLabx
1814 //
1815 CassyLabx::CassyLabx(const string& filename) : GenericFile(filename)
1816 {
1817 // Empty constructor
1818 }
1819
1820
1822 {
1823 // Empty destructor
1824 }
1825
1826
1836 {
1837 // Open the filestream in text mode
1838 open(ios::in);
1839
1840 string sLabx = "";
1841 string sLabx_substr = "";
1842 long long int nLine = 0;
1843
1844 // Get the whole content of the file in a
1845 // single string
1846 while (!fFileStream.eof())
1847 {
1848 getline(fFileStream, sLabx_substr);
1849 StripSpaces(sLabx_substr);
1850 sLabx += sLabx_substr;
1851 }
1852
1853 // Ensure that the least minimal information
1854 // is available in the file
1855 if (!sLabx.length() || sLabx.find("<allchannels count=") == string::npos)
1857
1858 // Extract the information on the number of
1859 // data sets in the file
1860 sLabx_substr = sLabx.substr(sLabx.find("<allchannels count="));
1861 sLabx_substr = sLabx_substr.substr(sLabx_substr.find("=\"")+2, sLabx_substr.find("\">")-sLabx_substr.find("=\"")-2);
1862 nCols = StrToInt(sLabx_substr);
1863
1864 // Ensure that there is at least one column
1865 // of data available
1866 if (!nCols)
1868
1869 vector<string> vHeadLines;
1870 vector<string> vCols;
1871
1872 // Start extracting the actual data from the
1873 // file
1874 sLabx_substr = sLabx.substr(sLabx.find("<allchannels"), sLabx.find("</allchannels>")-sLabx.find("<allchannels"));
1875 sLabx_substr = sLabx_substr.substr(sLabx_substr.find("<channels"));
1876
1877 // Distribute the different data columns
1878 // across the previously created vector
1879 for (long long int i = 0; i < nCols; i++)
1880 {
1881 // Push the current column to the
1882 // column vector
1883 vCols.push_back(sLabx_substr.substr(sLabx_substr.find("<values"), sLabx_substr.find("</channel>")-sLabx_substr.find("<values")));
1884
1885 // Store the headline of the current
1886 // column in the corresponding
1887 // headline vector. Consider also the
1888 // possible available unit
1889 if (sLabx_substr.find("<unit />") != string::npos && sLabx_substr.find("<unit />") < sLabx_substr.find("<unit>"))
1890 vHeadLines.push_back(sLabx_substr.substr(sLabx_substr.find("<quantity>")+10, sLabx_substr.find("</quantity>")-sLabx_substr.find("<quantity>")-10));
1891 else
1892 {
1893 vHeadLines.push_back(sLabx_substr.substr(sLabx_substr.find("<quantity>")+10, sLabx_substr.find("</quantity>")-sLabx_substr.find("<quantity>")-10)
1894 + "_[" + sLabx_substr.substr(sLabx_substr.find("<unit>")+6, sLabx_substr.find("</unit>")-sLabx_substr.find("<unit>")-6) + "]");
1895 }
1896
1897 // Convert UTF8 to WinCP1252 and erase the
1898 // already extracted part from the string
1899 vHeadLines.back() = utf8parser(vHeadLines.back());
1900 sLabx_substr.erase(0, sLabx_substr.find("</channels>")+11);
1901
1902 // Determine the maximal number of rows needed
1903 // for the overall data table
1904 if (StrToInt(vCols[i].substr(vCols[i].find("count=\"")+7, vCols[i].find("\">")-vCols[i].find("count=\"")-7)) > nLine)
1905 nLine = StrToInt(vCols[i].substr(vCols[i].find("count=\"")+7, vCols[i].find("\">")-vCols[i].find("count=\"")-7));
1906 }
1907
1908 // Ensure that the columns are not empty
1909 if (!nLine)
1911
1912 nRows = nLine;
1913
1914 // Prepare the internal storage and copy
1915 // the already decoded headlines
1916 createStorage();
1917
1918 for (long long int i = 0; i < nCols; i++)
1919 {
1920 fileData->at(i).reset(new ValueColumn);
1921 fileData->at(i)->m_sHeadLine = vHeadLines[i];
1922 }
1923
1924 long long int nElements = 0;
1925
1926 // Extract the numerical values directly
1927 // from the XML string into the internal
1928 // storage
1929 for (long long int i = 0; i < nCols; i++)
1930 {
1931 // Only do something, if the current
1932 // column contains some values
1933 if (vCols[i].find("<values count=\"0\" />") == string::npos)
1934 {
1935 // Get the number of elements in
1936 // the current column
1937 nElements = StrToInt(vCols[i].substr(vCols[i].find('"')+1,
1938 vCols[i].find('"', vCols[i].find('"')+1)-1-vCols[i].find('"')));
1939 vCols[i].erase(0, vCols[i].find('>')+1);
1940
1941 // Copy the elements into the internal
1942 // storage
1943 for (long long int j = 0; j < min(nElements, nRows); j++)
1944 {
1945 fileData->at(i)->setValue(j, extractValueFromTag(vCols[i].substr(vCols[i].find("<value"),
1946 vCols[i].find('<', vCols[i].find('/'))-vCols[i].find("<value"))));
1947 vCols[i].erase(0, vCols[i].find('>', vCols[i].find('/'))+1);
1948 }
1949 }
1950 }
1951
1952 }
1953
1954
1963 double CassyLabx::extractValueFromTag(const string& sTag)
1964 {
1965 return StrToDb(sTag.substr(7, sTag.find('<', 7)-7));
1966 }
1967
1968
1970 // class CommaSeparatedValues
1972 //
1974 {
1975 // Empty constructor
1976 }
1977
1978
1980 {
1981 // Empty destructor
1982 }
1983
1984
1993 {
1994 // Open the file stream in text mode
1995 open(ios::in);
1996
1997 // Create the needed variabels
1998 char cSep = 0;
1999 long long int nLine = 0;
2000 long long int nComment = 0;
2001 vector<string> vHeadLine;
2002
2003 // Read the whole file to a vector and
2004 // get the number of lines available in
2005 // the data file
2006 vector<string> vFileData = readTextFile(true);
2007 nLine = vFileData.size();
2008
2009 // Ensure that there is at least one
2010 // line available
2011 if (!nLine)
2013
2014 // Determine, which character is used
2015 // as cell separator
2016 cSep = findSeparator(vFileData);
2017
2018 // Ensure that we were able to determine
2019 // the separator
2020 if (!cSep)
2022
2023 // Count the number of columns available
2024 // in the file and ensure that the identified
2025 // separator character is correct
2026 countColumns(vFileData, cSep);
2027
2028 vHeadLine.resize(nCols);
2029
2030 // Define the set of valid letters numeric and
2031 // append the separator character
2032 string sValidSymbols = "0123456789.,;-+eE INFAinfa/";
2033 sValidSymbols += cSep;
2034
2035 // Search for non-numeric characters in the first
2036 // line of the file. Extract the possible table
2037 // column heads and note, when the table heads were
2038 // extracted from the file
2039 if (vFileData[0].find_first_not_of(sValidSymbols) != string::npos)
2040 {
2041 // Tokenize the current line using the
2042 // separator character
2043 vector<string> vTokens = tokenize(vFileData[0], string(1, cSep));
2044
2045 for (size_t i = 0; i < vTokens.size(); i++)
2046 {
2047 if (isConvertible(vTokens[i], CONVTYPE_VALUE))
2048 {
2049 vTokens.clear();
2050 break;
2051 }
2052 }
2053
2054 // Copy the tokenized strings to the target
2055 // table column headline vector
2056 for (size_t n = 0; n < (vTokens.size() < nCols ? vTokens.size() : nCols); n++)
2057 {
2058 vHeadLine[n] = utf8parser(vTokens[n]);
2059 StripSpaces(vHeadLine[n]);
2060 }
2061
2062 // Clear the first line, if the tokens were
2063 // not erased before
2064 if (vTokens.size())
2065 {
2066 vFileData[0].clear();
2067 nComment++;
2068 }
2069 }
2070
2071 // Store the number of lines of the file,
2072 // which contain numeric data, in the rows
2073 // variable
2074 if (nComment)
2075 nRows = nLine - 1;
2076 else
2077 nRows = nLine;
2078
2079 // Prepare the internal storage
2080 createStorage();
2081
2082 // We start with string-only and try to
2083 // convert them later
2084 for (long long int j = 0; j < nCols; j++)
2085 {
2086 fileData->at(j).reset(new StringColumn);
2087 }
2088
2089 // Copy the already decoded table heads to
2090 // the internal storage or create a dummy
2091 // column head, if the data contains only
2092 // one column
2093 if (nComment)
2094 {
2095 for (long long int j = 0; j < nCols; j++)
2096 {
2097 fileData->at(j)->m_sHeadLine = vHeadLine[j];
2098 }
2099 }
2100 else
2101 {
2102 // If the file contains only one column,
2103 // then we'll use the file name as table
2104 // column head
2105 if (nCols == 1)
2106 {
2107 if (sFileName.find('/') == string::npos)
2108 fileData->at(0)->m_sHeadLine = sFileName.substr(0, sFileName.rfind('.'));
2109 else
2110 fileData->at(0)->m_sHeadLine = sFileName.substr(sFileName.rfind('/')+1, sFileName.rfind('.')-1-sFileName.rfind('/'));
2111 }
2112 }
2113
2114 // Decode now the whole data table into single
2115 // tokens, which can be distributed into their
2116 // corresponding cells
2117 for (size_t i = nComment; i < vFileData.size(); i++)
2118 {
2119 // Ignore empty lines
2120 if (!vFileData[i].length())
2121 continue;
2122
2123 // Tokenize the current line
2124 vector<string> vTokens = tokenize(vFileData[i], string(1, cSep));
2125
2126 // Decode each token
2127 for (size_t j = 0; j < vTokens.size(); j++)
2128 {
2129 // Ensure that enough space is available
2130 if (j >= nCols)
2131 break;
2132
2133 fileData->at(j)->setValue(i-nComment, vTokens[j]);
2134 }
2135 }
2136 }
2137
2138
2148 {
2149 // Open the file in text mode and truncate
2150 // all its contents
2151 open(ios::out | ios::trunc);
2152
2153 // Write the table heads to the file
2154 for (long long int j = 0; j < nCols; j++)
2155 {
2156 if (fileData->at(j))
2157 fFileStream << fileData->at(j)->m_sHeadLine;
2158
2159 fFileStream << ",";
2160 }
2161
2162 fFileStream << "\n";
2163 fFileStream.precision(nPrecFields);
2164
2165 // Write the data to the file
2166 for (long long int i = 0; i < nRows; i++)
2167 {
2168 for (long long int j = 0; j < nCols; j++)
2169 {
2170 if (fileData->at(j) && fileData->at(j)->isValid(i))
2171 {
2172 if (fileData->at(j)->m_type == TableColumn::TYPE_VALUE)
2173 fFileStream << toString(fileData->at(j)->getValue(i), DEFAULT_PRECISION);
2174 else
2175 fFileStream << fileData->at(j)->getValueAsInternalString(i);
2176 }
2177
2178 fFileStream << ",";
2179 }
2180
2181 fFileStream << "\n";
2182 }
2183
2184 fFileStream.flush();
2185 }
2186
2187
2199 char CommaSeparatedValues::findSeparator(const vector<string>& vTextData)
2200 {
2201 char cSep = 0;
2202
2203 if (vTextData[0].find('.') != string::npos && vTextData[0].find(',') != string::npos && vTextData[0].find('\t') != string::npos)
2204 cSep = ',';
2205 else if (vTextData[0].find(';') != string::npos && (vTextData[0].find(',') != string::npos || vTextData[0].find('.') != string::npos) && vTextData[0].find('\t') != string::npos)
2206 cSep = ';';
2207 else if (vTextData[0].find('\t') != string::npos)
2208 cSep = '\t';
2209 else if (vTextData[0].find(';') != string::npos)
2210 cSep = ';';
2211 else if (vTextData[0].find(',') != string::npos)
2212 cSep = ',';
2213 else if (vTextData[0].find(' ') != string::npos && vTextData.size() > 1 && vTextData[1].find(' ') != string::npos)
2214 cSep = ' ';
2215 else
2216 {
2217 if (vTextData[0].find(',') != string::npos)
2218 cSep = ',';
2219 else if (vTextData[0].find(';') != string::npos)
2220 cSep = ';';
2221 else if (vTextData[0].find('\t') != string::npos)
2222 cSep = '\t';
2223 else if (vTextData[0].find(' ') != string::npos)
2224 cSep = ' ';
2225 else
2226 cSep = ','; // Fallback if this file does only contain a single column
2227
2228 size_t cols = 0;
2229
2230 // To ensure the selection of the current
2231 // separator character, we try to determine
2232 // the number of columns. If the this number
2233 // does not alter between the lines, then we
2234 // found the correct character
2235 for (size_t i = 0; i < vTextData.size(); i++)
2236 {
2237 size_t nCol = 1;
2238
2239 for (size_t j = 0; j < vTextData[i].length(); j++)
2240 {
2241 if (vTextData[i][j] == cSep)
2242 nCol++;
2243 }
2244
2245 if (!cols)
2246 cols = nCol;
2247 else if (nCol != cols)
2248 {
2249 if (cSep == ',')
2250 cSep = ';';
2251 else if (cSep == ';')
2252 cSep = ',';
2253 else if (cSep == '\t')
2254 cSep = ' ';
2255 else if (cSep == ' ')
2256 cSep = '\t';
2257
2258 cols = 0;
2259 }
2260 else
2261 return cSep;
2262
2263 if (i+1 == vTextData.size())
2264 return 0;
2265 }
2266 }
2267
2268 return cSep;
2269 }
2270
2271
2284 void CommaSeparatedValues::countColumns(const std::vector<std::string>& vTextData, char& cSep)
2285 {
2286 long long int nCol;
2287
2288 for (size_t i = 0; i < vTextData.size(); i++)
2289 {
2290 nCol = 1;
2291
2292 for (size_t j = 0; j < vTextData[i].length(); j++)
2293 {
2294 if (vTextData[i][j] == cSep)
2295 nCol++;
2296 }
2297
2298 if (nCols < nCol)
2299 nCols = nCol;
2300 else if (abs(nCol - nCols) > 1)
2301 {
2302 if (cSep == ',')
2303 cSep = ';';
2304 else if (cSep == ';')
2305 cSep = ',';
2306 else if (cSep == '\t')
2307 cSep = ' ';
2308 else if (cSep == ' ')
2309 cSep = '\t';
2310
2311 nCols = 0;
2312 }
2313 else
2314 return;
2315
2316 if (i+1 == vTextData.size())
2318 }
2319 }
2320
2321
2323 // class LaTeXTable
2325 //
2326 LaTeXTable::LaTeXTable(const string& filename) : GenericFile(filename)
2327 {
2328 // Empty constructor
2329 }
2330
2331
2333 {
2334 // Empty destructor
2335 }
2336
2337
2347 {
2348 // Open the file in text mode and
2349 // truncate all its contents
2350 open(ios::trunc | ios::out);
2351
2352 // Prepare a label for the table
2353 string sLabel = sFileName;
2354
2355 if (sLabel.find('/') != string::npos)
2356 sLabel.erase(0, sLabel.rfind('/')+1);
2357
2358 if (sLabel.find(".tex") != string::npos)
2359 sLabel.erase(sLabel.rfind(".tex"));
2360
2361 while (sLabel.find(' ') != string::npos)
2362 sLabel[sLabel.find(' ')] = '_';
2363
2364 // Write the legal header stuff
2365 writeHeader();
2366
2367 // Depending on the number of lines
2368 // in the current table, the layout
2369 // switches between usual and longtables
2370 //
2371 // Write the table column headers and
2372 // all needed layout stuff
2373 if (nRows < 30)
2374 {
2375 fFileStream << "\\begin{table}[htb]\n";
2376 fFileStream << "\\centering\n";
2377 string sPrint = "\\begin{tabular}{";
2378
2379 for (long long int j = 0; j < nCols; j++)
2380 sPrint += "c";
2381
2382 sPrint += "}";
2383 fFileStream << sPrint + "\n";
2384 fFileStream << "\\toprule\n";
2385
2387 }
2388 else
2389 {
2390 string sPrint = "\\begin{longtable}{";
2391
2392 for (long long int j = 0; j < nCols; j++)
2393 sPrint += "c";
2394
2395 sPrint += "}";
2396 fFileStream << sPrint + "\n";
2397 fFileStream << "\\caption{" + _lang.get("OUTPUT_FORMAT_TEX_HEAD", "NumeRe")+"}\n";
2398 fFileStream << "\\label{tab:" + sLabel + "}\\\\\n";
2399 fFileStream << "\\toprule\n";
2400
2402
2403 fFileStream << sPrint + "\n";
2404 fFileStream << "\\midrule\n";
2405 fFileStream << "\\endfirsthead\n";
2406 fFileStream << "\\caption{"+_lang.get("OUTPUT_FORMAT_TEXLONG_CAPTION")+"}\\\\\n";
2407 fFileStream << "\\toprule\n";
2408 fFileStream << sPrint;
2409 fFileStream << "\\midrule\n";
2410 fFileStream << "\\endhead\n";
2411 fFileStream << "\\midrule\n";
2412 fFileStream << "\\multicolumn{" + toString(nCols) + "}{c}{--- \\emph{"+_lang.get("OUTPUT_FORMAT_TEXLONG_FOOT")+"} ---}\\\\\n";
2413 fFileStream << "\\bottomrule\n";
2414 fFileStream << "\\endfoot\n";
2415 fFileStream << "\\bottomrule\n";
2416 fFileStream << "\\endlastfoot\n";
2417 }
2418
2419 // Write the actual data formatted as
2420 // LaTeX numbers into the file and insert
2421 // the needed column separators
2422 for (long long int i = 0; i < nRows; i++)
2423 {
2424 for (long long int j = 0; j < nCols; j++)
2425 {
2426 fFileStream.width(nPrecFields+20);
2427 fFileStream.fill(' ');
2428
2429 if (!fileData->at(j))
2430 fFileStream << "---";
2431 else if (fileData->at(j)->m_type == TableColumn::TYPE_VALUE)
2432 fFileStream << formatNumber(fileData->at(j)->getValue(i));
2433 else
2434 fFileStream << fileData->at(j)->getValueAsInternalString(i);
2435
2436 if (j+1 < nCols)
2437 fFileStream << " &";
2438 else
2439 fFileStream << "\\\\\n";
2440 }
2441 }
2442
2443 // Finalize the table. This also depends
2444 // on the number of lines in the internal
2445 // storage
2446 if (nRows < 30)
2447 {
2448 fFileStream << "\\bottomrule\n";
2449 fFileStream << "\\end{tabular}\n";
2450 fFileStream << "\\caption{"+ _lang.get("OUTPUT_FORMAT_TEX_HEAD", "NumeRe")+"}\n";
2451 fFileStream << "\\label{tab:" + sLabel + "}\n";
2452 fFileStream << "\\end{table}\n";
2453 }
2454 else
2455 {
2456 fFileStream << "\\end{longtable}\n";
2457 }
2458
2459 fFileStream << flush;
2460 }
2461
2462
2471 {
2472 string sBuild = AutoVersion::YEAR;
2473 sBuild += "-";
2474 sBuild += AutoVersion::MONTH;
2475 sBuild += "-";
2476 sBuild += AutoVersion::DATE;
2477
2478 fFileStream << "%\n";
2479 fFileStream << "% " + _lang.get("OUTPUT_PRINTLEGAL_LINE1") << "\n";
2480 fFileStream << "% NumeRe: Framework für Numerische Rechnungen" << "\n";
2481 fFileStream << "%=============================================" << "\n";
2482 fFileStream << "% " + _lang.get("OUTPUT_PRINTLEGAL_LINE2", sVersion, sBuild) << "\n";
2483 fFileStream << "% " + _lang.get("OUTPUT_PRINTLEGAL_LINE3", sBuild.substr(0, 4)) << "\n";
2484 fFileStream << "%\n";
2485 fFileStream << "% " + _lang.get("OUTPUT_PRINTLEGAL_LINE4", getTimeStamp(false)) << "\n";
2486 fFileStream << "%\n";
2487 fFileStream << "% " + _lang.get("OUTPUT_PRINTLEGAL_TEX") << "\n%" << endl;
2488 }
2489
2490
2501 {
2502 string sPrint = "";
2503
2504 // Copy the contents to the string and
2505 // consider the number of lines needed
2506 // for the headlines
2507 for (size_t i = 0; i < countHeadLines(); i++)
2508 {
2509 for (long long int j = 0; j < nCols; j++)
2510 sPrint += getLineFromHead(j, i) + " & ";
2511
2512 sPrint = sPrint.substr(0, sPrint.length()-2) + "\\\\\n";
2513 }
2514
2515 // Remove the underscores from the whole
2516 // string, because they would interfere
2517 // with LaTeX
2518 for (size_t i = 0; i < sPrint.length(); i++)
2519 {
2520 if (sPrint[i] == '_')
2521 sPrint[i] = ' ';
2522 }
2523
2524 fFileStream << sPrint;
2525 }
2526
2527
2537 {
2538 size_t headlines = 0u;
2539
2540 // Get the cell extents of each table
2541 // column head and store the maximal
2542 // value
2543 for (long long int i = 0; i < nCols; i++)
2544 {
2545 if (!fileData->at(i))
2546 continue;
2547
2548 auto extents = calculateCellExtents(fileData->at(i)->m_sHeadLine);
2549
2550 if (extents.second > headlines)
2551 headlines = extents.second;
2552 }
2553
2554 return headlines;
2555 }
2556
2557
2567 string LaTeXTable::replaceNonASCII(const string& _sText)
2568 {
2569 string sReturn = _sText;
2570
2571 for (unsigned int i = 0; i < sReturn.length(); i++)
2572 {
2573 if (sReturn[i] == 'Ä' || sReturn[i] == (char)142)
2574 sReturn.replace(i,1,"\\\"A");
2575
2576 if (sReturn[i] == 'ä' || sReturn[i] == (char)132)
2577 sReturn.replace(i,1,"\\\"a");
2578
2579 if (sReturn[i] == 'Ö' || sReturn[i] == (char)153)
2580 sReturn.replace(i,1,"\\\"O");
2581
2582 if (sReturn[i] == 'ö' || sReturn[i] == (char)148)
2583 sReturn.replace(i,1,"\\\"o");
2584
2585 if (sReturn[i] == 'Ü' || sReturn[i] == (char)154)
2586 sReturn.replace(i,1,"\\\"U");
2587
2588 if (sReturn[i] == 'ü' || sReturn[i] == (char)129)
2589 sReturn.replace(i,1,"\\\"u");
2590
2591 if (sReturn[i] == 'ß' || sReturn[i] == (char)225)
2592 sReturn.replace(i,1,"\\ss ");
2593
2594 if (sReturn[i] == '°' || sReturn[i] == (char)248)
2595 sReturn.replace(i,1,"$^\\circ$");
2596
2597 if (sReturn[i] == (char)196 || sReturn[i] == (char)249)
2598 sReturn.replace(i,1,"\\pm ");
2599
2600 if (sReturn[i] == (char)171 || sReturn[i] == (char)174)
2601 sReturn.replace(i,1,"\"<");
2602
2603 if (sReturn[i] == (char)187 || sReturn[i] == (char)175)
2604 sReturn.replace(i,1,"\">");
2605
2606 if ((!i && sReturn[i] == '_') || (i && sReturn[i] == '_' && sReturn[i-1] != '\\'))
2607 sReturn.insert(i,1,'\\');
2608 }
2609
2610 if (sReturn.find("+/-") != string::npos)
2611 {
2612 sReturn = sReturn.substr(0, sReturn.find("+/-"))
2613 + "$\\pm$"
2614 + sReturn.substr(sReturn.find("+/-")+3);
2615 }
2616
2617 return sReturn;
2618 }
2619
2620
2630 {
2631 string sNumber = toString(number, nPrecFields);
2632
2633 // Handle floating point numbers with
2634 // exponents correctly
2635 while (sNumber.find('e') != std::string::npos)
2636 {
2637 sNumber = sNumber.substr(0, sNumber.find('e'))
2638 + "\\cdot10^{"
2639 + (sNumber[sNumber.find('e')+1] == '-' ? "-" : "")
2640 + sNumber.substr(sNumber.find_first_not_of('0', sNumber.find('e')+2))
2641 + "}";
2642 }
2643
2644 // Consider some special values
2645 if (sNumber == "inf")
2646 sNumber = "\\infty";
2647
2648 if (sNumber == "-inf")
2649 sNumber = "-\\infty";
2650
2651 if (sNumber == "nan")
2652 return "---";
2653
2654 // Return the formatted string in math mode
2655 return "$" + sNumber + "$";
2656 }
2657
2658
2660 // class JcampDX
2662 //
2663 JcampDX::JcampDX(const string& filename) : GenericFile(filename)
2664 {
2665 // Empty constructor
2666 }
2667
2668
2670 {
2671 // Empty destructor
2672 }
2673
2674
2675
2681 {
2683 {
2685 XY, // (XY), (X,Y)
2686 XY_XY, // (XY..XY), (X,Y..X,Y)
2687 XppY_Y, // ((X++)(Y..Y))
2688 XPPY_Y // (X++(Y..Y))
2690
2691 size_t m_points;
2695 double m_firstX;
2696 double m_lastX;
2697 double m_deltaX;
2698
2699 std::string m_xUnit;
2700 std::string m_yUnit;
2701 std::string m_symbol;
2702
2704 };
2705
2706
2716 {
2717 // Open the file in text mode
2718 open(ios::in);
2719
2720 // Create some temporary buffer variables
2721 size_t nTableStart = 0;
2722 std::vector<MetaData> vMeta(1u);
2723
2724 nRows = 0;
2725 nCols = 0;
2726
2727 // Read the contents of the file to the
2728 // vector variable
2729 std::vector<std::string> vFileContents = readTextFile(true);
2730
2731 // Ensure that contents are available
2732 if (!vFileContents.size())
2734
2735 // Find the end tag in the file and omit
2736 // all following lines
2737 for (size_t i = 0; i < vFileContents.size(); i++)
2738 {
2739 StripSpaces(vFileContents[i]);
2740
2741 // Copy all meta data before the actual table into
2742 // a common string
2743 if (vFileContents[i].substr(0, 2) == "##"
2744 && !nTableStart
2745 && vFileContents[i].substr(0, 6) != "##END=")
2746 {
2747 if (sComment.length())
2748 sComment += "\n";
2749
2750 sComment += vFileContents[i].substr(2);
2751 }
2752
2753 parseLabel(vFileContents[i]);
2754
2755 // Here starts a n-tuples table
2756 if (vFileContents[i].substr(0, 10) == "##NTUPLES=")
2757 {
2765
2766 for (size_t j = i+1; j < vFileContents.size(); j++)
2767 {
2768 StripSpaces(vFileContents[j]);
2769
2770 // Copy all meta data before the actual table into
2771 // a common string
2772 if (vFileContents[j].substr(0, 2) == "##"
2773 && vFileContents[j].substr(0, 7) != "##PAGE=")
2774 {
2775 if (sComment.length())
2776 sComment += "\n";
2777
2778 sComment += vFileContents[j].substr(2);
2779 }
2780
2781 parseLabel(vFileContents[j]);
2782
2783 if (vFileContents[j].substr(0, 9) == "##SYMBOL=")
2784 symbol = getAllArguments(vFileContents[j].substr(9));
2785 else if (vFileContents[j].substr(0, 10) == "##VARTYPE=")
2786 varType = getAllArguments(vFileContents[j].substr(10));
2787 else if (vFileContents[j].substr(0, 9) == "##VARDIM=")
2788 varDim = getAllArguments(vFileContents[j].substr(9));
2789 else if (vFileContents[j].substr(0, 8) == "##UNITS=")
2790 units = getAllArguments(vFileContents[j].substr(8));
2791 else if (vFileContents[j].substr(0, 8) == "##FIRST=")
2792 firstVal = getAllArguments(vFileContents[j].substr(8));
2793 else if (vFileContents[j].substr(0, 7) == "##LAST=")
2794 lastVal = getAllArguments(vFileContents[j].substr(7));
2795 else if (vFileContents[j].substr(0, 9) == "##FACTOR=")
2796 factor = getAllArguments(vFileContents[j].substr(9));
2797 else if (vFileContents[j].substr(0, 7) == "##PAGE=")
2798 {
2799 nTableStart = j;
2800 i = j;
2801
2802 // Decode the read meta table
2803 size_t dependentCount = 0;
2804
2805 // Create MetaData objects for all dependent
2806 // variables first
2807 for (size_t n = 0; n < varType.size(); n++)
2808 {
2809 if (varType[n] == "DEPENDENT")
2810 {
2811 dependentCount++;
2812
2813 if (dependentCount > vMeta.size())
2814 vMeta.push_back(MetaData());
2815
2816 vMeta.back().m_symbol = symbol[n];
2817 vMeta.back().m_yUnit = units[n];
2818
2819 if (varDim[n].size())
2820 vMeta.back().m_points = StrToInt(varDim[n]);
2821
2822 if (factor[n].size())
2823 vMeta.back().m_yFactor = StrToDb(factor[n]);
2824 }
2825 }
2826
2827 // Insert the values of the main independent variable
2828 // into the MetaData objects for all dependent variables
2829 for (size_t n = 0; n < varType.size(); n++)
2830 {
2831 if (varType[n] == "INDEPENDENT" && symbol[n] == "X")
2832 {
2833 for (MetaData& meta : vMeta)
2834 {
2835 meta.m_xUnit = units[n];
2836
2837 if (factor[n].size())
2838 meta.m_xFactor = StrToDb(factor[n]);
2839
2840 if (firstVal[n].size())
2841 meta.m_firstX = StrToDb(firstVal[n]);
2842
2843 if (lastVal[n].size())
2844 meta.m_lastX = StrToDb(lastVal[n]);
2845 }
2846
2847 break;
2848 }
2849 }
2850
2851 break;
2852 }
2853 }
2854 }
2855
2856 // Erase everything after the end tag
2857 if (vFileContents[i].substr(0, 6) == "##END=")
2858 {
2859 vFileContents.erase(vFileContents.begin()+i+1, vFileContents.end());
2860 break;
2861 }
2862 }
2863
2864 size_t page = 0;
2865
2866 // Read all pages available in the file
2867 do
2868 {
2869 nTableStart = readTable(vFileContents, nTableStart, vMeta.size() > page ? vMeta[page] : vMeta.front());
2870 page++;
2871 }
2872 while (nTableStart + 1 < vFileContents.size());
2873
2874 // Find maximal number of rows
2875 for (long long int j = 0; j < nCols; j++)
2876 {
2877 if (fileData->at(j)->size() > nRows)
2878 nRows = fileData->at(j)->size();
2879 }
2880 }
2881
2882
2893 size_t JcampDX::readTable(std::vector<std::string>& vFileContents, size_t nTableStart, JcampDX::MetaData meta)
2894 {
2895 std::vector<double> vLine;
2896 long long int nPageOffset = nCols;
2897 size_t nDataStart = 0;
2898
2899 // Find the start of the data table
2900 for (size_t i = nTableStart; i < vFileContents.size(); i++)
2901 {
2902 // Determine the needed number of rows
2903 if (vFileContents[i].substr(0, 10) == "##NPOINTS=")
2904 meta.m_points = StrToInt(vFileContents[i].substr(10));
2905
2906 if (vFileContents[i].substr(0,11) == "##XYPOINTS="
2907 || vFileContents[i].substr(0, 9) == "##XYDATA="
2908 || vFileContents[i].substr(0, 12) == "##PEAKTABLE="
2909 || vFileContents[i].substr(0, 12) == "##DATATABLE=")
2910 {
2911 nDataStart = i+1;
2912 std::string sXYScheme = vFileContents[i].substr(vFileContents[i].find('=')+1);
2913 StripSpaces(sXYScheme);
2914
2915 // Remove all internal whitespaces
2916 while (sXYScheme.find(' ') != std::string::npos)
2917 sXYScheme.erase(sXYScheme.find(' '), 1);
2918
2919 // Remove all trailing information like "PEAKS"
2920 if (sXYScheme.rfind(')')+1 < sXYScheme.length())
2921 sXYScheme.erase(sXYScheme.rfind(')')+1);
2922
2923 // If other variables are used than Y, replace them here
2924 if (sXYScheme.find('Y') == std::string::npos && meta.m_symbol.length())
2925 replaceAll(sXYScheme, meta.m_symbol.c_str(), "Y");
2926
2927 // Detect the data format
2928 if (sXYScheme == "(XY..XY)" || sXYScheme == "(X,Y..X,Y)")
2930 else if (sXYScheme == "(XY)" || sXYScheme == "(X,Y)")
2931 meta.m_format = MetaData::XY;
2932 else if (sXYScheme == "(X++(Y..Y))")
2934 else if (sXYScheme == "(X++)(Y..Y)")
2936
2937 break;
2938 }
2939 }
2940
2941 if (!meta.m_points || !nDataStart || meta.m_format == MetaData::NO_FORMAT)
2943
2944 // Determine the number of needed columns based upon the data
2945 // table type and the first row, if necessary
2946 nCols += 2;
2947
2948 // Prepare the internal storage
2949 if (!fileData)
2951
2952 fileData->resize(nCols);
2953
2954 // We only create numerical columns for this data type
2955 for (long long int j = nPageOffset; j < nCols; j++)
2956 {
2957 fileData->at(j).reset(new ValueColumn);
2958 }
2959
2960 // Prepare some decoding variables
2961 std::string sDataType = "";
2962
2963 // Go through the label section first
2964 // and decode the header information of
2965 // the data set
2966 for (size_t j = nTableStart; j < nDataStart-1; j++)
2967 {
2968 // Omit comments
2969 if (vFileContents[j].find("$$") != string::npos)
2970 vFileContents[j].erase(vFileContents[j].find("$$"));
2971
2972 // Get the x and y scaling factors
2973 if (vFileContents[j].substr(0,10) == "##XFACTOR=")
2974 meta.m_xFactor = StrToDb(vFileContents[j].substr(10));
2975
2976 if (vFileContents[j].substr(0,10) == "##YFACTOR=")
2977 meta.m_yFactor = StrToDb(vFileContents[j].substr(10));
2978
2979 if (vFileContents[j].substr(0,9) == "##FIRSTX=")
2980 meta.m_firstX = StrToDb(vFileContents[j].substr(9));
2981
2982 if (vFileContents[j].substr(0,8) == "##LASTX=")
2983 meta.m_lastX = StrToDb(vFileContents[j].substr(8));
2984
2985 // Extract the x units
2986 if (vFileContents[j].substr(0,9) == "##XUNITS=")
2987 {
2988 meta.m_xUnit = vFileContents[j].substr(9);
2989 StripSpaces(meta.m_xUnit);
2990 }
2991
2992 // Extract the y units
2993 if (vFileContents[j].substr(0,9) == "##YUNITS=")
2994 {
2995 meta.m_yUnit = vFileContents[j].substr(9);
2996 StripSpaces(meta.m_yUnit);
2997 }
2998
2999 // Get the data type (currently unused)
3000 if (vFileContents[j].substr(0,11) == "##DATATYPE=")
3001 {
3002 sDataType = vFileContents[j].substr(11);
3003 StripSpaces(sDataType);
3004 }
3005 }
3006
3007 if (meta.m_xUnit.length())
3008 {
3009 if (toUpperCase(meta.m_xUnit) == "1/CM")
3010 meta.m_xUnit = "Wellenzahl k [cm^-1]";
3011 else if (toUpperCase(meta.m_xUnit) == "MICROMETERS")
3012 meta.m_xUnit = "Wellenlänge lambda [mu m]";
3013 else if (toUpperCase(meta.m_xUnit) == "NANOMETERS")
3014 meta.m_xUnit = "Wellenlänge lambda [nm]";
3015 else if (toUpperCase(meta.m_xUnit) == "SECONDS")
3016 meta.m_xUnit = "Zeit t [s]";
3017 else if (toUpperCase(meta.m_xUnit) == "1/S" || toUpperCase(meta.m_xUnit) == "1/SECONDS")
3018 meta.m_xUnit = "Frequenz f [Hz]";
3019 else
3020 meta.m_xUnit = "[" + meta.m_xUnit + "]";
3021 }
3022
3023 if (meta.m_yUnit.length())
3024 {
3025 if (toUpperCase(meta.m_yUnit) == "TRANSMITTANCE")
3026 meta.m_yUnit = "Transmission";
3027 else if (toUpperCase(meta.m_yUnit) == "REFLECTANCE")
3028 meta.m_yUnit = "Reflexion";
3029 else if (toUpperCase(meta.m_yUnit) == "ABSORBANCE")
3030 meta.m_yUnit = "Absorbtion";
3031 else if (toUpperCase(meta.m_yUnit) == "KUBELKA-MUNK")
3032 meta.m_yUnit = "Kubelka-Munk";
3033 else if (toUpperCase(meta.m_yUnit) == "ARBITRARY UNITS" || meta.m_yUnit.substr(0,9) == "Intensity")
3034 meta.m_yUnit = "Intensität";
3035 }
3036
3037 meta.m_deltaX = (meta.m_lastX - meta.m_firstX) / (meta.m_points - 1);
3038 size_t currentRow = 0;
3039 fileData->at(nPageOffset + 0)->m_sHeadLine = meta.m_xUnit;
3040 fileData->at(nPageOffset + 1)->m_sHeadLine = meta.m_yUnit;
3041
3042 // Now go through the actual data section
3043 // of the file and convert it into
3044 // numerical values
3045 for (size_t j = nDataStart; j < vFileContents.size() - 1; j++)
3046 {
3047 // Abort at the end tag
3048 if (vFileContents[j].substr(0, 6) == "##END="
3049 || vFileContents[j].substr(0, 7) == "##PAGE=")
3050 return j;
3051
3052 // Ignore lables
3053 if (vFileContents[j].substr(0, 2) == "##")
3054 continue;
3055
3056 // Omit comments
3057 if (vFileContents[j].find("$$") != string::npos)
3058 {
3059 vFileContents[j].erase(vFileContents[j].find("$$"));
3060 StripSpaces(vFileContents[j]);
3061 }
3062
3063 // Abort, if we have enough lines
3064 if (currentRow >= meta.m_points)
3065 return j;
3066
3067 // Decode the current line
3068 vLine = parseLine(vFileContents[j]);
3069
3070 if (!vLine.size())
3071 {
3072 NumeReKernel::issueWarning("Parsing of line " + toString(j+1) + " yield no result.");
3073 continue;
3074 }
3075
3076 // Interpret the line depending on the JDX format
3077 if (meta.m_format == MetaData::XY || meta.m_format == MetaData::XY_XY) // XY pairs
3078 {
3079 for (size_t k = 0; k < vLine.size(); k++)
3080 {
3081 fileData->at(nPageOffset + k % 2)->setValue(currentRow, vLine[k] * (k % 2 ? meta.m_yFactor : meta.m_xFactor));
3082 currentRow += k % 2;
3083 }
3084 }
3085 else if (meta.m_format == MetaData::XPPY_Y) // first value has to be identical to calculated one
3086 {
3087 if (std::abs(meta.m_firstX+meta.m_deltaX*currentRow - vLine[0]*meta.m_xFactor) > std::abs(meta.m_deltaX) * 1e-1)
3088 NumeReKernel::issueWarning("Missing points in JCAMP-DX file in line " + toString(j+1)
3089 + ". Expected: " + toString(meta.m_firstX+meta.m_deltaX*currentRow)
3090 + " Found: " + toString(vLine[0]*meta.m_xFactor));
3091
3092 fileData->at(nPageOffset + 0)->setValue(currentRow, meta.m_firstX + meta.m_deltaX * currentRow);
3093 fileData->at(nPageOffset + 1)->setValue(currentRow, vLine[1] * meta.m_yFactor);
3094 currentRow++;
3095
3096 for (size_t k = 2; k < vLine.size(); k++)
3097 {
3098 fileData->at(nPageOffset + 0)->setValue(currentRow, meta.m_firstX + meta.m_deltaX * currentRow);
3099 fileData->at(nPageOffset + 1)->setValue(currentRow, vLine[k] * meta.m_yFactor);
3100 currentRow++;
3101 }
3102 }
3103 else if (meta.m_format == MetaData::XppY_Y) // No X value
3104 {
3105 for (size_t k = 0; k < vLine.size(); k++)
3106 {
3107 fileData->at(nPageOffset + 0)->setValue(currentRow, meta.m_firstX + meta.m_deltaX * currentRow);
3108 fileData->at(nPageOffset + 1)->setValue(currentRow, vLine[k] * meta.m_yFactor);
3109 currentRow++;
3110 }
3111 }
3112 }
3113
3114 return vFileContents.size();
3115 }
3116
3117
3128 void JcampDX::parseLabel(string& sLine)
3129 {
3130 if (sLine.find("##") == string::npos || sLine.find('=') == string::npos)
3131 return;
3132
3133 for (size_t i = 0; i < sLine.length(); i++)
3134 {
3135 // Remove some characters
3136 if (sLine[i] == ' ' || sLine[i] == '-' || sLine[i] == '_')
3137 {
3138 sLine.erase(i, 1);
3139 i--;
3140 }
3141
3142 // Transform to uppercase
3143 if (sLine[i] >= 'a' && sLine[i] <= 'z')
3144 sLine[i] += 'A'-'a';
3145
3146 // Stop at the equal sign
3147 if (sLine[i] == '=')
3148 break;
3149 }
3150 }
3151
3152
3153
3167 std::vector<double> JcampDX::parseLine(const std::string& sLine)
3168 {
3169 std::vector<double> vLine;
3170 std::string sValue = "";
3171 const std::string sNumericChars = "0123456789.+-";
3172 double lastDiff = 0;
3173
3174 // Go through the complete line and uncompress
3175 // the data into usual text strings, which will
3176 // be stored in another string
3177 for (size_t i = sLine.find_first_not_of(" \t"); i < sLine.length(); i++)
3178 {
3179 // The first three cases are the simplest
3180 // cases, where the data is not compressed
3181 if ((sLine[i] >= '0' && sLine[i] <= '9') || sLine[i] == '.')
3182 sValue += sLine[i];
3183 else if (sValue.length()
3184 && (sLine[i] == 'e' || sLine[i] == 'E')
3185 && sLine.length() > i+2
3186 && (sLine[i] == '+' || sLine[i] == '-')
3187 && sNumericChars.find(sValue[0]) != std::string::npos)
3188 sValue += sLine[i];
3189 else if (sValue.length()
3190 && (sLine[i] == '+' || sLine[i] == '-')
3191 && sNumericChars.find(sValue[0]) != std::string::npos
3192 && (sValue[sValue.length()-1] == 'e' || sValue[sValue.length()-1] == 'E'))
3193 sValue += sLine[i];
3194 else
3195 {
3196 // This section is for compressed data
3197 // DIFDUP form. Only the first character
3198 // is compressed
3199 if (sValue.length())
3200 {
3201 if ((sValue[0] >= 'J' && sValue[0] <= 'R'))
3202 {
3203 // Positive DIF digits
3204 sValue[0] = toString(sValue[0]-'J'+1)[0];
3205 lastDiff = StrToDb(sValue);
3206 vLine.push_back(vLine.back()+lastDiff);
3207 }
3208 else if ((sValue[0] >= 'j' && sValue[0] <= 'r'))
3209 {
3210 // Negative DIF digits
3211 sValue[0] = toString(sValue[0]-'j'+1)[0];
3212 lastDiff = -StrToDb(sValue);
3213 vLine.push_back(vLine.back()+lastDiff);
3214 }
3215 else if (sValue[0] == '%')
3216 {
3217 // A zero
3218 lastDiff = 0;
3219 vLine.push_back(vLine.back());
3220 }
3221 else if ((sValue[0] >= 'S' && sValue[0] <= 'Z') || sValue[0] == 's')
3222 {
3223 // DUP digits
3224 if (sValue[0] == 's')
3225 sValue[0] = '9';
3226 else
3227 sValue[0] = sValue[0]-'S'+'1';
3228
3229 int iter = StrToInt(sValue);
3230
3231 for (int j = 0; j < iter-1; j++)
3232 vLine.push_back(vLine.back()+lastDiff);
3233
3234 lastDiff = 0;
3235 }
3236 else
3237 {
3238 lastDiff = 0;
3239 vLine.push_back(StrToDb(sValue)); // Simply convert into a double
3240 }
3241
3242 sValue.clear();
3243 }
3244
3245 // We convert SQZ digits directly in
3246 // their plain format
3247 if (sLine[i] >= 'A' && sLine[i] <= 'I')
3248 sValue += toString(sLine[i]-'A'+1)[0];
3249 else if (sLine[i] >= 'a' && sLine[i] <= 'i')
3250 sValue += toString('a'-sLine[i]-1);
3251 else if (sLine[i] == '@')
3252 vLine.push_back(0);
3253 else if (sLine[i] == '%' && vLine.size() && sLine.size() > i+1)
3254 {
3255 vLine.push_back(vLine.back());
3256 lastDiff = 0;
3257 }
3258 else if ((vLine.size()
3259 && ((sLine[i] >= 'J' && sLine[i] <= 'R')
3260 || (sLine[i] >= 'j' && sLine[i] <= 'r')
3261 || (sLine[i] >= 'S' && sLine[i] <= 'Z')
3262 || sLine[i] == 's'))
3263 || sLine[i] == '+'
3264 || sLine[i] == '-')
3265 sValue += sLine[i];
3266 }
3267 }
3268
3269 // This section is for compressed data
3270 // DIFDUP form. Only the first character
3271 // is compressed
3272 if (sValue.length())
3273 {
3274 if (vLine.size() == 1)
3275 {
3276 if ((sValue[0] >= 'J' && sValue[0] <= 'R'))
3277 {
3278 // Positive DIF digits
3279 sValue[0] = toString(sValue[0]-'J'+1)[0];
3280 vLine.push_back(vLine.back()+StrToDb(sValue));
3281 }
3282 else if ((sValue[0] >= 'j' && sValue[0] <= 'r'))
3283 {
3284 // Negative DIF digits
3285 sValue[0] = toString(sValue[0]-'j'+1)[0];
3286 vLine.push_back(vLine.back()-StrToDb(sValue));
3287 }
3288 else if (sValue[0] == '%')
3289 {
3290 // A zero
3291 vLine.push_back(vLine.back());
3292 }
3293 }
3294
3295 if ((sValue[0] >= 'S' && sValue[0] <= 'Z') || sValue[0] == 's')
3296 {
3297 // DUP digits
3298 if (sValue[0] == 's')
3299 sValue[0] = '9';
3300 else
3301 sValue[0] = sValue[0]-'S'+'1';
3302
3303 int iter = StrToInt(sValue);
3304
3305 if (iter == 1)
3306 vLine.pop_back();
3307 else
3308 {
3309 for (int j = 0; j < iter-2; j++)
3310 vLine.push_back(vLine.back()+lastDiff);
3311 }
3312
3313 lastDiff = 0;
3314 }
3315 else if (isdigit(sValue[0]) || sValue[0] == '+' || sValue[0] == '-')
3316 vLine.push_back(StrToDb(sValue)); // Simply convert into a double
3317
3318 sValue.clear();
3319 }
3320
3321 return vLine;
3322 }
3323
3324
3326 // class OpenDocumentSpreadSheet
3328 //
3330 {
3331 // Empty constructor
3332 }
3333
3334
3336 {
3337 // Empty destructor
3338 }
3339
3340
3351 {
3352 string sODS = "";
3353 string sODS_substr = "";
3354 vector<string> vTables;
3355 vector<string> vMatrix;
3356 long long int nCommentLines = 0;
3357 long long int nMaxCols = 0;
3358
3359 // Get the contents of the embedded
3360 // XML file
3361 sODS = getZipFileItem("content.xml");
3362
3363 // Ensure that the embedded file is
3364 // not empty
3365 if (!sODS.length())
3367
3368 // Remove the obsolete beginning of
3369 // the file, which we don't need
3370 sODS.erase(0, sODS.find("<office:spreadsheet>"));
3371
3372 // Ensure again that the file is not empty
3373 if (!sODS.length())
3375
3376 // Remove the part until the first table
3377 sODS.erase(0, sODS.find("<table:table "));
3378
3379 // Extract the different tables from the
3380 // whole string and store them in different
3381 // vector components
3382 while (sODS.size() && sODS.find("<table:table ") != string::npos && sODS.find("</table:table>") != string::npos)
3383 {
3384 vTables.push_back(sODS.substr(sODS.find("<table:table "), sODS.find("</table:table>")+14-sODS.find("<table:table ")));
3385 sODS.erase(sODS.find("<table:table "), sODS.find("</table:table>")+14-sODS.find("<table:table "));
3386 }
3387
3388 // Ensure that we found at least a single
3389 // table
3390 if (!vTables.size())
3392
3393 // Decode all tables and store them next
3394 // to each other in the vMatrix vector
3395 // variable
3396 for (unsigned int i = 0; i < vTables.size(); i++)
3397 {
3398 unsigned int nPos = 0;
3399 unsigned int nCount = 0;
3400 long long int _nCols = 0;
3401 string sLine = "";
3402
3403 // This section decodes a single table and stores
3404 // the lines in the vMatrix vector variable. If
3405 // this is not the first table, then the lines
3406 // are appended to the already existing ones
3407 while (vTables[i].find("<table:table-row ", nPos) != string::npos && vTables[i].find("</table:table-row>", nPos) != string::npos)
3408 {
3409 // Extract the next line from the current
3410 // table and expand the line
3411 nPos = vTables[i].find("<table:table-row ", nPos);
3412 sLine = vTables[i].substr(nPos, vTables[i].find("</table:table-row>", nPos)+18-nPos);
3413 sLine = expandLine(sLine);
3414
3415 // If the line is not empty, store it
3416 // at the corresponding line in the vMatrix
3417 // variable
3418 if (sLine.length())
3419 {
3420 if (!i) // first table
3421 vMatrix.push_back(sLine);
3422 else
3423 {
3424 // Extent the number if rows with
3425 // empty cells, if the following tables
3426 // contain more rows
3427 if (vMatrix.size() <= nCount)
3428 {
3429 vMatrix.push_back("<>");
3430
3431 for (long long int n = 1; n < nMaxCols; n++)
3432 vMatrix[nCount] += "<>";
3433
3434 vMatrix[nCount] += sLine;
3435 }
3436 else
3437 vMatrix[nCount] += sLine;
3438
3439 nCount++;
3440 }
3441 }
3442
3443 nPos++;
3444 }
3445
3446 // Determine the current number of columns,
3447 // which are contained in the vMatrix variable
3448 // up to now
3449 for (unsigned int j = 0; j < vMatrix.size(); j++)
3450 {
3451 _nCols = 0;
3452
3453 // Each opening left angle brace corresponds
3454 // to a single cell
3455 for (unsigned int n = 0; n < vMatrix[j].length(); n++)
3456 {
3457 if (vMatrix[j][n] == '<')
3458 _nCols++;
3459 }
3460
3461 if (_nCols > nMaxCols)
3462 nMaxCols = _nCols;
3463 }
3464
3465 // Append empty cells to matrix rows, if their
3466 // number of columns is not sufficient to resemble
3467 // a full rectangle matrix
3468 for (unsigned int j = 0; j < vMatrix.size(); j++)
3469 {
3470 _nCols = 0;
3471
3472 // Each opening left angle brace corresponds
3473 // to a single cell
3474 for (unsigned int n = 0; n < vMatrix[j].length(); n++)
3475 {
3476 if (vMatrix[j][n] == '<')
3477 _nCols++;
3478 }
3479
3480 if (_nCols < nMaxCols)
3481 {
3482 for (long long int k = _nCols; k < nMaxCols; k++)
3483 vMatrix[j] += "<>";
3484 }
3485 }
3486 }
3487
3488 // Replace all whitespaces in the matrix
3489 // with underscores
3490 for (unsigned int i = 0; i < vMatrix.size(); i++)
3491 {
3492 while (vMatrix[i].find(' ') != string::npos)
3493 vMatrix[i].replace(vMatrix[i].find(' '), 1, "_");
3494 }
3495
3496 // Ensure that the matrix is not empty
3497 if (!vMatrix.size() || !nMaxCols)
3499
3500 // Try to detect the number of (pure)
3501 // text lines in the matrix. Those will be
3502 // used as table column heads. If a single
3503 // cell is numeric, we do not use this row
3504 // as a text line
3505 for (unsigned int i = 0; i < vMatrix.size(); i++)
3506 {
3507 bool bBreak = false;
3508
3509 for (unsigned int j = 0; j < vMatrix[i].length(); j++)
3510 {
3511 // Only examine non-empty cells
3512 if (vMatrix[i][j] == '<' && vMatrix[i][j+1] != '>')
3513 {
3514 // If this cell is numeric, leave the
3515 // whole loop
3516 if (isNumeric(vMatrix[i].substr(j+1, vMatrix[i].find('>',j)-j-1)))
3517 {
3518 bBreak = true;
3519 break;
3520 }
3521 }
3522
3523 if (j == vMatrix[i].length()-1)
3524 nCommentLines++;
3525 }
3526
3527 if (bBreak)
3528 break;
3529 }
3530
3531 // Set the dimensions of the final table
3532 // and create the internal storage
3533 nRows = vMatrix.size() - nCommentLines;
3534 nCols = nMaxCols;
3535 createStorage();
3536
3537 // We first create a string-only table and try to
3538 // convert them afterwards
3539 for (long long int j = 0; j < nCols; j++)
3540 {
3541 fileData->at(j).reset(new StringColumn);
3542 }
3543
3544 unsigned int nPos = 0;
3545
3546 // Store the pure text lines as table
3547 // column heads
3548 for (long long int i = 0; i < nCommentLines; i++)
3549 {
3550 nPos = 0;
3551
3552 for (long long int j = 0; j < nCols; j++)
3553 {
3554 nPos = vMatrix[i].find('<', nPos);
3555 string sEntry = utf8parser(vMatrix[i].substr(nPos,vMatrix[i].find('>', nPos)+1-nPos));
3556 nPos++;
3557
3558 // Omit empty cells
3559 if (sEntry == "<>")
3560 continue;
3561
3562 // Remove the left and right angles
3563 sEntry.erase(0, 1);
3564 sEntry.pop_back();
3565
3566 if (!fileData->at(j)->m_sHeadLine.length())
3567 fileData->at(j)->m_sHeadLine = sEntry;
3568 else if (fileData->at(j)->m_sHeadLine != sEntry)
3569 fileData->at(j)->m_sHeadLine += "\n" + sEntry;
3570 }
3571 }
3572
3573 // Store the actual data in the internal
3574 // storage. If we hit a text-only cell,
3575 // then we'll append it to the corresponding
3576 // table column head
3577 for (long long int i = 0; i < nRows; i++)
3578 {
3579 nPos = 0;
3580
3581 for (long long int j = 0; j < nCols; j++)
3582 {
3583 nPos = vMatrix[i+nCommentLines].find('<', nPos);
3584 string sEntry = utf8parser(vMatrix[i+nCommentLines].substr(nPos,vMatrix[i+nCommentLines].find('>', nPos)+1-nPos));
3585 nPos++;
3586
3587 // Omit empty cells
3588 if (sEntry == "<>")
3589 continue;
3590
3591 // Remove left and right angles
3592 sEntry.erase(0, 1);
3593 sEntry.pop_back();
3594
3595 // Write it as a string to the table
3596 fileData->at(j)->setValue(i, sEntry);
3597 }
3598 }
3599 }
3600
3601
3613 string OpenDocumentSpreadSheet::expandLine(const string& sLine)
3614 {
3615 string sExpandedLine = "";
3616
3617 for (unsigned int i = 0; i < sLine.length(); i++)
3618 {
3619 if (sLine.substr(i, 17) == "<table:table-cell")
3620 {
3621 if (sLine[sLine.find('>',i)-1] != '/')
3622 {
3623 // Read the value of the current cell
3624 string sCellEntry = sLine.substr(i, sLine.find("</table:table-cell>", i)-i);
3625
3626 // Extract the value into a simpler,
3627 // intermediate cell format: "<VALUE>"
3628 if (sCellEntry.find("office:value-type=") != string::npos && getArgAtPos(sCellEntry, sCellEntry.find("office:value-type=")+18) == "float")
3629 sExpandedLine += "<" + getArgAtPos(sCellEntry, sCellEntry.find("office:value=")+13) + ">";
3630 else if (sCellEntry.find("<text:p>") != string::npos)
3631 sExpandedLine += "<" + sCellEntry.substr(sCellEntry.find("<text:p>")+8, sCellEntry.find("</text:p>")-sCellEntry.find("<text:p>")-8) + ">";
3632 }
3633 else
3634 {
3635 if (sLine.find("<table:table-cell", i+1) == string::npos && sLine.find("<table:covered-table-cell", i+1) == string::npos)
3636 break;
3637
3638 if (sLine.substr(i, sLine.find('>',i)+1-i).find("table:number-columns-repeated=") != string::npos)
3639 {
3640 // If there are some empty cells,
3641 // which are compressed, then we
3642 // expand them here
3643 string sTemp = getArgAtPos(sLine, sLine.find("table:number-columns-repeated=", i)+30);
3644
3645 if (sTemp.front() == '"')
3646 sTemp.erase(0, 1);
3647
3648 if (sTemp.back() == '"')
3649 sTemp.pop_back();
3650
3651 // Create the corresponding number
3652 // of empty cells
3653 for (int j = 0; j < StrToInt(sTemp); j++)
3654 sExpandedLine += "<>";
3655 }
3656 else
3657 sExpandedLine += "<>";
3658 }
3659 }
3660 else if (sLine.substr(i,25) == "<table:covered-table-cell")
3661 {
3662 // If there are some empty cells,
3663 // which are compressed, then we
3664 // expand them here
3665 string sTemp = getArgAtPos(sLine, sLine.find("table:number-columns-repeated=", i)+30);
3666
3667 if (sTemp.front() == '"')
3668 sTemp.erase(0, 1);
3669
3670 if (sTemp.back() == '"')
3671 sTemp.pop_back();
3672
3673 // Create the corresponding number
3674 // of empty cells
3675 for (int j = 0; j < StrToInt(sTemp); j++)
3676 sExpandedLine += "<>";
3677 }
3678 }
3679
3680 // Remove all trailing empty cells from the
3681 // current line. If they are necessary to
3682 // create a rectangular table, then they
3683 // will be added again
3684 if (sExpandedLine.length())
3685 {
3686 while (sExpandedLine.substr(sExpandedLine.length()-2) == "<>")
3687 {
3688 sExpandedLine.erase(sExpandedLine.length()-2);
3689
3690 if (!sExpandedLine.length() || sExpandedLine.length() < 2)
3691 break;
3692 }
3693 }
3694
3695 return sExpandedLine;
3696 }
3697
3698
3700 // class XLSSpreadSheet
3702 //
3703 XLSSpreadSheet::XLSSpreadSheet(const string& filename) : GenericFile(filename)
3704 {
3705 // Empty constructor
3706 }
3707
3708
3710 {
3711 // Empty destructor
3712 }
3713
3714
3724 {
3725 YExcel::BasicExcel _excel;
3728 unsigned int nSheets = 0;
3729 long long int nExcelLines = 0;
3730 long long int nExcelCols = 0;
3731 long long int nOffset = 0;
3732 long long int nCommentLines = 0;
3733 vector<long long int> vCommentLines;
3734 bool bBreakSignal = false;
3735 string sEntry;
3736
3737 // Ensure that the XLS file is readable
3738 if (!_excel.Load(sFileName.c_str()))
3740
3741 // get the total number of sheets
3742 nSheets = _excel.GetTotalWorkSheets();
3743
3744 // Ensure that we have at least a single
3745 // sheet in the file
3746 if (!nSheets)
3748
3749 // get the total size needed for all sheets,
3750 // which will be stored next to each other. We
3751 // consider pure text lines as table column
3752 // heads
3753 for (unsigned int n = 0; n < nSheets; n++)
3754 {
3755 _sheet = _excel.GetWorksheet(n);
3756 bBreakSignal = false;
3757 nCommentLines = 0;
3758
3759 for (unsigned int i = 0; i < _sheet->GetTotalRows(); i++)
3760 {
3761 for (unsigned int j = 0; j < _sheet->GetTotalCols(); j++)
3762 {
3763 // Abort the loop, if we find a single
3764 // non-textual cell in the current row
3765 if (_sheet->Cell(i,j)->Type() != YExcel::BasicExcelCell::STRING
3766 && _sheet->Cell(i,j)->Type() != YExcel::BasicExcelCell::WSTRING
3767 && _sheet->Cell(i,j)->Type() != YExcel::BasicExcelCell::UNDEFINED)
3768 {
3769 bBreakSignal = true;
3770 break;
3771 }
3772 }
3773
3774 if (bBreakSignal)
3775 break;
3776
3777 nCommentLines++;
3778 }
3779
3780 vCommentLines.push_back(nCommentLines != 0);
3781
3782 // Find the maximal number of needed rows
3783 if (nExcelLines < _sheet->GetTotalRows()-(nCommentLines != 0))
3784 nExcelLines = _sheet->GetTotalRows()-(nCommentLines != 0);
3785
3786 // Add the number of columns of the current
3787 // sheet to the total number of columns
3788 nExcelCols += _sheet->GetTotalCols();
3789 }
3790
3791 // Set the dimensions of the needed internal
3792 // storage and create it
3793 nRows = nExcelLines;
3794 nCols = nExcelCols;
3795 createStorage();
3796
3797 // We create a string-only table and try to convert it
3798 // afterwards
3799 for (long long int j = 0; j < nCols; j++)
3800 {
3801 fileData->at(j).reset(new StringColumn);
3802 }
3803
3804 // Copy the pure text lines into the corresponding
3805 // table column heads
3806 for (unsigned int n = 0; n < nSheets; n++)
3807 {
3808 _sheet = _excel.GetWorksheet(n);
3809 nExcelCols = _sheet->GetTotalCols();
3810 nExcelLines = _sheet->GetTotalRows();
3811
3812 // We only use the pure text lines from the top
3813 for (long long int i = 0; i < vCommentLines[n]; i++)
3814 {
3815 if (i >= nExcelLines)
3816 break;
3817
3818 for (long long int j = 0; j < nExcelCols; j++)
3819 {
3820 if (j+nOffset >= nCols)
3821 break;
3822
3823 _cell = _sheet->Cell(i,j);
3824
3825 if (_cell->Type() == YExcel::BasicExcelCell::STRING)
3826 sEntry = utf8parser(_cell->GetString());
3827 else if (_cell->Type() == YExcel::BasicExcelCell::WSTRING)
3828 sEntry = utf8parser(wcstombs(_cell->GetWString()));
3829 else
3830 continue;
3831
3832 // Replace line break characters with their
3833 // corresponding masked character
3834 while (sEntry.find((char)13) != string::npos)
3835 sEntry.replace(sEntry.find((char)13), 1, "\n");
3836
3837 // Append the string to the current table
3838 // column head, if it is not empty
3839 if (!fileData->at(j+nOffset)->m_sHeadLine.length())
3840 fileData->at(j+nOffset)->m_sHeadLine = sEntry;
3841 else if (fileData->at(j+nOffset)->m_sHeadLine != sEntry)
3842 fileData->at(j+nOffset)->m_sHeadLine += "\n" + sEntry;
3843 }
3844 }
3845
3846 nOffset += nExcelCols;
3847 }
3848
3849 nOffset = 0;
3850
3851 // Copy now the data to the internal storage.
3852 // We consider textual cells as part of the
3853 // corresponding table column heads and append
3854 // them automatically
3855 for (unsigned int n = 0; n < nSheets; n++)
3856 {
3857 _sheet = _excel.GetWorksheet(n);
3858 nExcelCols = _sheet->GetTotalCols();
3859 nExcelLines = _sheet->GetTotalRows();
3860
3861 for (long long int i = vCommentLines[n]; i < nExcelLines; i++)
3862 {
3863 if (i - vCommentLines[n] >= nRows)
3864 break;
3865
3866 for (long long int j = 0; j < nExcelCols; j++)
3867 {
3868 if (j >= nCols)
3869 break;
3870
3871 _cell = _sheet->Cell(i,j);
3872
3873 // Select the type of the cell and
3874 // store the value, if it's a number
3875 switch (_cell->Type())
3876 {
3878 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], "");
3879 break;
3881 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], (double)_cell->GetInteger());
3882 break;
3884 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], _cell->GetDouble());
3885 break;
3887 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], utf8parser(_cell->GetString()));
3888 break;
3890 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], utf8parser(wcstombs(_cell->GetWString())));
3891 break;
3892 default:
3893 fileData->at(j+nOffset)->setValue(i-vCommentLines[n], "");
3894 }
3895 }
3896 }
3897
3898 nOffset += nExcelCols;
3899 }
3900 }
3901
3902
3912 {
3913 YExcel::BasicExcel _excel;
3916
3917 string sHeadLine;
3918 string sSheetName = getTableName();
3919
3920 // Create a new sheet
3921 _excel.New(1);
3922
3923 // Rename it so that it fits the cache name
3924 _excel.RenameWorksheet(0u, sSheetName.c_str());
3925
3926 // Get a pointer to this sheet
3927 _sheet = _excel.GetWorksheet(0u);
3928
3929 // Write the headlines in the first row
3930 for (long long int j = 0; j < nCols; j++)
3931 {
3932 // Get the current cell and the headline string
3933 _cell = _sheet->Cell(0u, j);
3934
3935 if (fileData->at(j))
3936 sHeadLine = fileData->at(j)->m_sHeadLine;
3937
3938 // Replace newlines with the corresponding character code
3939 while (sHeadLine.find('\n') != string::npos)
3940 sHeadLine.replace(sHeadLine.find('\n'), 2, 1, (char)10);
3941
3942 // Write the headline
3943 _cell->SetString(sHeadLine.c_str());
3944 }
3945
3946 // Now write the actual table
3947 for (long long int i = 0; i < nRows; i++)
3948 {
3949 for (long long int j = 0; j < nCols; j++)
3950 {
3951 // Get the current cell (skip over the first row, because it contains the headline)
3952 _cell = _sheet->Cell(1 + i, j);
3953
3954 // Write the cell contents, if the data table contains valid data
3955 // otherwise clear the cell
3956 if (!fileData->at(j) || !fileData->at(j)->isValid(i))
3957 {
3958 _cell->EraseContents();
3959 continue;
3960 }
3961
3962 if (fileData->at(j)->m_type == TableColumn::TYPE_VALUE || fileData->at(j)->m_type == TableColumn::TYPE_LOGICAL)
3963 _cell->SetDouble(fileData->at(j)->getValue(i).real());
3964 else
3965 _cell->SetString(fileData->at(j)->getValueAsInternalString(i).c_str());
3966 }
3967 }
3968
3969 // Save the excel file with the target filename
3970 _excel.SaveAs(sFileName.c_str());
3971 }
3972
3973
3975 // class XLSXSpreadSheet
3977 //
3978 XLSXSpreadSheet::XLSXSpreadSheet(const string& filename) : GenericFile(filename)
3979 {
3980 // Empty constructor
3981 }
3982
3983
3985 {
3986 // Empty destructor
3987 }
3988
3989
4000 {
4001 unsigned int nSheets = 0;
4002 long long int nExcelLines = 0;
4003 long long int nExcelCols = 0;
4004 long long int nOffset = 0;
4005 int nLine = 0, nCol = 0;
4006 int nLinemin = 0, nLinemax = 0;
4007 int nColmin = 0, nColmax = 0;
4008 bool bBreakSignal = false;
4009
4010 vector<long long int> vCommentLines;
4011 string sEntry;
4012 string sSheetContent;
4013 string sStringsContent;
4014 string sCellLocation;
4015
4016 // We use TinyXML-2 as XML libary in this case
4017 tinyxml2::XMLDocument _workbook;
4018 tinyxml2::XMLDocument _sheet;
4019 tinyxml2::XMLDocument _strings;
4020 tinyxml2::XMLNode* _node;
4021 tinyxml2::XMLElement* _element;
4022 tinyxml2::XMLElement* _stringelement;
4023
4024 // Get the content of the workbool XML file
4025 sEntry = getZipFileItem("xl/workbook.xml");
4026
4027 // Ensure that a workbook XML is available
4028 if (!sEntry.length())
4030
4031 // Parse the file to obtain the number of
4032 // sheets, which are associated with this
4033 // workbook
4034 _workbook.Parse(sEntry.c_str());
4035
4036 // Ensure that we could parse the file correctly
4037 if (_workbook.ErrorID())
4039
4040 // Search the first child of the "sheets" node
4041 // in the current workbook and count all siblings
4042 _node = _workbook.FirstChildElement()->FirstChildElement("sheets")->FirstChild();
4043
4044 if (_node)
4045 nSheets++;
4046
4047 while ((_node = _node->NextSibling()))
4048 nSheets++;
4049
4050 // Ensure that we have at least one sheet in
4051 // the workbook
4052 if (!nSheets)
4054
4055 // Walk through the sheets and extract the
4056 // dimension info
4057 for (unsigned int i = 0; i < nSheets; i++)
4058 {
4059 // Get the file contents of the current
4060 // sheet
4061 sSheetContent = getZipFileItem("xl/worksheets/sheet"+toString(i+1)+".xml");
4062
4063 // Ensure that the sheet is not empty
4064 if (!sSheetContent.length())
4066
4067 // Parse the sheet and catch parsing
4068 // errors
4069 _sheet.Parse(sSheetContent.c_str());
4070
4071 if (_sheet.ErrorID())
4073
4074 // Get the dimensions of the current sheet
4075 _element = _sheet.FirstChildElement()->FirstChildElement("dimension");
4076 sCellLocation = _element->Attribute("ref");
4077 int nLinemin = 0, nLinemax = 0;
4078 int nColmin = 0, nColmax = 0;
4079
4080 // Take care of comment lines => todo
4081 evalIndices(sCellLocation.substr(0, sCellLocation.find(':')), nLinemin, nColmin);
4082 evalIndices(sCellLocation.substr(sCellLocation.find(':') + 1), nLinemax, nColmax);
4083
4084 vCommentLines.push_back(0);
4085
4086 // Search the data section of the sheet
4087 _node = _sheet.FirstChildElement()->FirstChildElement("sheetData")->FirstChild();
4088
4089 if (!_node)
4090 continue;
4091
4092 // Find pure textual lines in the current
4093 // sheet, which will be used as table column
4094 // heads
4095 do
4096 {
4097 // Find the next cell
4098 _element = _node->ToElement()->FirstChildElement("c");
4099
4100 do
4101 {
4102 if (_element->Attribute("t"))
4103 {
4104 // If the attribute signalizes a
4105 // non-string element, we abort here
4106 if (_element->Attribute("t") != string("s"))
4107 {
4108 bBreakSignal = true;
4109 break;
4110 }
4111 }
4112 else
4113 {
4114 bBreakSignal = true;
4115 break;
4116 }
4117 }
4118 while ((_element = _element->NextSiblingElement()));
4119
4120 if (!bBreakSignal)
4121 vCommentLines[i]++;
4122 else
4123 break;
4124 }
4125 while ((_node = _node->NextSibling()));
4126
4127 bBreakSignal = false;
4128
4129 // Calculate the maximal number of needed
4130 // rows to store all sheets next to each
4131 // other
4132 if (nExcelLines < nLinemax-nLinemin+1-vCommentLines[i])
4133 nExcelLines = nLinemax-nLinemin+1-vCommentLines[i];
4134
4135 // Add the number of columns to the total
4136 // number of columns
4137 nExcelCols += nColmax-nColmin+1;
4138 }
4139
4140 // Set the dimensions of the final table
4141 nRows = nExcelLines;
4142 nCols = nExcelCols;
4143
4144 // Allocate the memory
4145 createStorage();
4146
4147 // We create a text-only table first
4148 for (long long int j = 0; j < nCols; j++)
4149 {
4150 fileData->at(j).reset(new StringColumn);
4151 }
4152
4153 // Walk through the sheets and extract the
4154 // contents to memory
4155 //
4156 // Get the contents of the shared strings
4157 // XML file and parse it
4158 sStringsContent = getZipFileItem("xl/sharedStrings.xml");
4159 _strings.Parse(sStringsContent.c_str());
4160
4161 // Go through all sheets
4162 for (unsigned int i = 0; i < nSheets; i++)
4163 {
4164 // Get the file contents of the current
4165 // sheet and parse it
4166 sSheetContent = getZipFileItem("xl/worksheets/sheet"+toString(i+1)+".xml");
4167 _sheet.Parse(sSheetContent.c_str());
4168
4169 // Search the data section and the dimensions
4170 // of the current sheet
4171 _node = _sheet.FirstChildElement()->FirstChildElement("sheetData")->FirstChild();
4172 _element = _sheet.FirstChildElement()->FirstChildElement("dimension");
4173
4174 // Ensure that data is available
4175 if (!_node)
4176 continue;
4177
4178 // Extract the target indices
4179 sCellLocation = _element->Attribute("ref");
4180 evalIndices(sCellLocation.substr(0, sCellLocation.find(':')), nLinemin, nColmin);
4181 evalIndices(sCellLocation.substr(sCellLocation.find(':')+1), nLinemax, nColmax);
4182
4183 // Go through each cell and store its
4184 // value at the correct position in the
4185 // final table. If we hit a textual cell,
4186 // then we store its contents as a table
4187 // column head
4188 do
4189 {
4190 _element = _node->ToElement()->FirstChildElement("c");
4191
4192 if (!_element)
4193 continue;
4194
4195 // Go through the cells of the current
4196 // row
4197 do
4198 {
4199 sCellLocation = _element->Attribute("r");
4200 evalIndices(sCellLocation, nLine, nCol);
4201 nCol -= nColmin;
4202 nLine -= nLinemin;
4203
4204 if (nCol+nOffset >= nCols || nLine-vCommentLines[i] >= nRows)
4205 continue;
4206
4207 // catch textual cells and store them
4208 // in the corresponding table column
4209 // head
4210 if (_element->Attribute("t"))
4211 {
4212 if (_element->Attribute("t") == string("s"))
4213 {
4214 //Handle text
4215 int nPos = 0;
4216 _element->FirstChildElement("v")->QueryIntText(&nPos);
4217 _stringelement = _strings.FirstChildElement()->FirstChildElement("si");
4218
4219 for (int k = 1; k <= nPos; k++)
4220 {
4221 _stringelement = _stringelement->NextSiblingElement();
4222 }
4223
4224 if (_stringelement->FirstChildElement()->FirstChild())
4225 sEntry = utf8parser(_stringelement->FirstChildElement()->FirstChild()->ToText()->Value());
4226 else
4227 sEntry.clear();
4228
4229 // If the string is not empty, then
4230 // we'll add it to the correct table
4231 // column head
4232 if (sEntry.length())
4233 {
4234 if (nLine - vCommentLines[i] < 0)
4235 {
4236 if (!fileData->at(nCol+nOffset)->m_sHeadLine.length())
4237 fileData->at(nCol+nOffset)->m_sHeadLine = sEntry;
4238 else if (fileData->at(nCol+nOffset)->m_sHeadLine != sEntry)
4239 fileData->at(nCol+nOffset)->m_sHeadLine += "\n" + sEntry;
4240 }
4241 else
4242 fileData->at(nCol+nOffset)->setValue(nLine-vCommentLines[i], sEntry);
4243 }
4244
4245 continue;
4246 }
4247 }
4248 else if (_element->FirstChildElement("v"))
4249 {
4250 fileData->at(nCol+nOffset)->setValue(nLine-vCommentLines[i], _element->FirstChildElement("v")->GetText());
4251 }
4252 }
4253 while ((_element = _element->NextSiblingElement()));
4254 }
4255 while ((_node = _node->NextSibling()));
4256
4257 nOffset += nColmax-nColmin+1;
4258 }
4259 }
4260
4261
4272 void XLSXSpreadSheet::evalIndices(const string& _sIndices, int& nLine, int& nCol)
4273 {
4274 //A1 -> IV65536
4275 string sIndices = toUpperCase(_sIndices);
4276
4277 for (size_t i = 0; i < sIndices.length(); i++)
4278 {
4279 // Find the first character,
4280 // which is a digit: that's a
4281 // line index
4282 if (isdigit(sIndices[i]))
4283 {
4284 // Convert the line index
4285 nLine = StrToInt(sIndices.substr(i))-1;
4286
4287 // Convert the column index.
4288 // This index might be two
4289 // characters long
4290 if (i == 2)
4291 nCol = (sIndices[0]-'A'+1)*26+sIndices[1]-'A';
4292 else if (i == 1)
4293 nCol = sIndices[0]-'A';
4294
4295 break;
4296 }
4297 }
4298 }
4299
4300
4302 // class IgorBinaryWave
4304 //
4305 IgorBinaryWave::IgorBinaryWave(const string& filename) : GenericFile(filename), bXZSlice(false)
4306 {
4307 // Empty constructor
4308 }
4309
4310
4319 {
4320 bXZSlice = file.bXZSlice;
4321 }
4322
4323
4325 {
4326 // Empty destructor
4327 }
4328
4329
4340 {
4341 CP_FILE_REF _cp_file_ref;
4342 int nType = 0;
4343 long nPnts = 0;
4344 void* vWaveDataPtr = nullptr;
4345 long long int nFirstCol = 0;
4346 long int nDim[MAXDIMS];
4347 double dScalingFactorA[MAXDIMS];
4348 double dScalingFactorB[MAXDIMS];
4349 bool bReadComplexData = false;
4350 int nSliceCounter = 0;
4351 float* fData = nullptr;
4352 double* dData = nullptr;
4353 int8_t* n8_tData = nullptr;
4354 int16_t* n16_tData = nullptr;
4355 int32_t* n32_tData = nullptr;
4356 char* cName = nullptr;
4357
4358 // Try to open the target file
4359 if (CPOpenFile(sFileName.c_str(), 0, &_cp_file_ref))
4361
4362 // Try to read the data from the
4363 // file into the passed void*
4364 if (ReadWave(_cp_file_ref, &nType, &nPnts, nDim, dScalingFactorA, dScalingFactorB, &vWaveDataPtr, &cName))
4365 {
4366 CPCloseFile(_cp_file_ref);
4367
4368 if (vWaveDataPtr != NULL)
4369 free(vWaveDataPtr);
4370
4372 }
4373
4374 // Detect complex data
4375 if (nType & NT_CMPLX)
4376 bReadComplexData = true;
4377
4378 // Convert the pointer into the correct
4379 // type
4380 if (nType & NT_FP32)
4381 fData = (float*)vWaveDataPtr;
4382 else if (nType & NT_FP64)
4383 dData = (double*)vWaveDataPtr;
4384 else if (nType & NT_I8)
4385 n8_tData = (int8_t*)vWaveDataPtr;
4386 else if (nType & NT_I16)
4387 n16_tData = (int16_t*)vWaveDataPtr;
4388 else if (nType & NT_I32)
4389 n32_tData = (int32_t*)vWaveDataPtr;
4390 else
4391 {
4392 CPCloseFile(_cp_file_ref);
4393
4394 if (vWaveDataPtr != nullptr)
4395 free(vWaveDataPtr);
4396
4398 }
4399
4400 // Obtain the final dimensions of
4401 // the whol table. A three-dimensional
4402 // wave will be rolled out in the
4403 // third dimension
4404 nRows = nDim[0];
4405 nCols = nDim[1];
4406
4407 if (nDim[2])
4408 nCols *= nDim[2];
4409
4410 // Ensure that data is available
4411 if (!nRows)
4412 {
4413 CPCloseFile(_cp_file_ref);
4414
4415 if (vWaveDataPtr != nullptr)
4416 free(vWaveDataPtr);
4417
4419 }
4420
4421 // Alter the column dimensions to
4422 // respect the data conventions of IGOR
4423 // (they do not store x-values)
4424 if (!nCols || nCols == 1)
4425 {
4426 nFirstCol = 1;
4427 nCols = 2;
4428 }
4429 else if (nDim[1] && (!nDim[2] || nDim[2] == 1))
4430 {
4431 nCols += 2;
4432 nFirstCol = 2;
4433
4434 if (nDim[1] > nDim[0])
4435 nRows = nDim[1];
4436 }
4437 else if (nDim[1] && nDim[2] && (!nDim[3] || nDim[3] == 1))
4438 {
4439 nCols += 3;
4440 nFirstCol = 3;
4441 nRows = nDim[2] > nRows ? nDim[2] : nRows;
4442 nRows = nDim[1] > nRows ? nDim[1] : nRows;
4443 }
4444
4445 // Create the internal storage using the
4446 // final dimensions
4447 createStorage();
4448
4449 // We create plain value column tables
4450 for (long long int j = 0; j < nCols; j++)
4451 {
4452 fileData->at(j).reset(new ValueColumn);
4453 }
4454
4455 // Fill the x column and its corresponding
4456 // table column head
4457 for (long long int j = 0; j < nFirstCol; j++)
4458 {
4459 fileData->at(j)->m_sHeadLine = cName + string("_[")+(char)('x'+j)+string("]");
4460
4461 for (long long int i = 0; i < nDim[j]; i++)
4462 {
4463 fileData->at(j)->setValue(i, dScalingFactorA[j]*(double)i + dScalingFactorB[j]);
4464 }
4465 }
4466
4467 // Fill the remaining data into the table
4468 // next to the x column
4469 for (long long int j = 0; j < nCols-nFirstCol; j++)
4470 {
4471 // Take respect on three-dimensional
4472 // waves and roll them out correctly
4473 if (bXZSlice && nDim[2] > 1 && j)
4474 {
4475 nSliceCounter += nDim[1];
4476
4477 if (!(j % nDim[2]))
4478 nSliceCounter = j/nDim[2];
4479 }
4480 else
4481 nSliceCounter = j;
4482
4483 // Write the corresponding table column
4484 // head
4485 if (nCols == 2 && !j)
4486 fileData->at(1)->m_sHeadLine = cName + string("_[y]");
4487 else
4488 fileData->at(j+nFirstCol)->m_sHeadLine = cName + string("_["+toString(j+1)+"]");
4489
4490 // Write the actual data to the table.
4491 // We have to take care about the type
4492 // of the data and whether the data is
4493 // complex or not
4494 long long int nInsertion = 0;
4495
4496 for (long long int i = 0; i < (nDim[0]+bReadComplexData*nDim[0]); i++)
4497 {
4498 if (dData)
4499 {
4500 if (bReadComplexData)
4501 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, mu::value_type(dData[i+j*2*nDim[0]], dData[i+1+j*2*nDim[0]]));
4502 else
4503 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, dData[i+j*(nDim[0])]);
4504 }
4505 else if (fData)
4506 {
4507 if (bReadComplexData)
4508 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, mu::value_type(fData[i+j*2*nDim[0]], fData[i+1+j*2*nDim[0]]));
4509 else
4510 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, (double)fData[i+j*(nDim[0])]);
4511 }
4512 else if (n8_tData)
4513 {
4514 if (bReadComplexData)
4515 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, mu::value_type(n8_tData[i+j*2*nDim[0]], n8_tData[i+1+j*2*nDim[0]]));
4516 else
4517 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, (double)n8_tData[i+j*(nDim[0])]);
4518
4519 }
4520 else if (n16_tData)
4521 {
4522 if (bReadComplexData)
4523 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, mu::value_type(n16_tData[i+j*2*nDim[0]], n16_tData[i+1+j*2*nDim[0]]));
4524 else
4525 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, (double)n16_tData[i+j*(nDim[0])]);
4526 }
4527 else if (n32_tData)
4528 {
4529 if (bReadComplexData)
4530 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, mu::value_type(n32_tData[i+j*2*nDim[0]], n32_tData[i+1+j*2*nDim[0]]));
4531 else
4532 fileData->at(nSliceCounter+nFirstCol)->setValue(nInsertion, (double)n32_tData[i+j*(nDim[0])]);
4533 }
4534
4535 nInsertion++;
4536 i += bReadComplexData;
4537 }
4538 }
4539
4540 // Close the file reference and
4541 // free the allocated memory
4542 CPCloseFile(_cp_file_ref);
4543
4544 if (vWaveDataPtr != nullptr)
4545 free(vWaveDataPtr);
4546 }
4547
4548
4558 {
4559 assign(file);
4560 bXZSlice = file.bXZSlice;
4561
4562 return *this;
4563 }
4564
4565
4567 // class ZygoDat
4569 //
4570 ZygoDat::ZygoDat(const string& filename) : GenericFile(filename)
4571 {
4572 // Empty constructor
4573 }
4574
4575
4584 {
4585 // Empty constructor
4586 }
4587
4588
4590 {
4591 // Empty destructor
4592 }
4593
4594
4605 {
4606 // Use the ZygoLib to open the file
4607 ZygoLib::DatFile zygofile(sFileName, false);
4608 std::vector<ZygoLib::InterferogramData> fileContent;
4609
4610 // Try to read its contents
4611 try
4612 {
4613 fileContent = zygofile.read();
4614 }
4615 catch (...)
4616 {
4618 }
4619
4620 // Determine the needed dimensions for the final
4621 // storage
4622 for (const ZygoLib::InterferogramData& layer : fileContent)
4623 {
4624 if (std::max(layer.header.cn_height, layer.header.cn_width) > nRows)
4625 nRows = std::max(layer.header.cn_height, layer.header.cn_width);
4626
4627 nCols += 2+layer.header.cn_height;
4628 }
4629
4630 // Ensure that we actually read something
4631 if (!nRows)
4633
4634 // Create the internal storage using the
4635 // final dimensions
4636 createStorage();
4637
4638 // We create plain value column tables
4639 for (long long int j = 0; j < nCols; j++)
4640 {
4641 fileData->at(j).reset(new ValueColumn);
4642 }
4643
4644 uint16_t colOffset = 0;
4645
4646 // Copy each layer to the target data
4647 for (const ZygoLib::InterferogramData& layer : fileContent)
4648 {
4649 fileData->at(colOffset)->m_sHeadLine = "x";
4650 fileData->at(colOffset+1)->m_sHeadLine = "y";
4651
4652 // Write the x column
4653 for (uint16_t i = 0; i < layer.header.cn_width; i++)
4654 {
4655 fileData->at(colOffset)->setValue(i, i * layer.header.camera_res);
4656 }
4657
4658 // Write the y column
4659 for (uint16_t j = 0; j < layer.header.cn_height; j++)
4660 {
4661 fileData->at(colOffset+1)->setValue(j, j * layer.header.camera_res);
4662 }
4663
4664 // Write the phase data and consider the needed transposition of height and width
4665 for (uint16_t i = 0; i < layer.header.cn_width; i++)
4666 {
4667 for (uint16_t j = 0; j < layer.header.cn_height; j++)
4668 {
4669 if (!i)
4670 fileData->at(j+colOffset+2)->m_sHeadLine = "z(x(:),y(" + toString(j+1) + "))";
4671
4672 fileData->at(j+colOffset+2)->setValue(i, layer.phaseMatrix[j][i]);
4673 }
4674 }
4675
4676 // The layers are put next to each other
4677 colOffset += 2+layer.header.cn_height;
4678 }
4679 }
4680
4681
4691 {
4692 assign(file);
4693 return *this;
4694 }
4695}
4696
4697
const std::string sVersion
int CPCloseFile(CP_FILE_REF fileRef)
int CPOpenFile(const char *fullFilePath, int readOrWrite, CP_FILE_REF *fileRefPtr)
#define CP_FILE_REF
#define NT_FP32
Definition: IgorBin.h:25
#define NT_FP64
Definition: IgorBin.h:26
#define MAXDIMS
Definition: IgorBin.h:34
#define NT_I32
Definition: IgorBin.h:29
#define NT_CMPLX
Definition: IgorBin.h:24
#define NT_I8
Definition: IgorBin.h:27
#define NT_I16
Definition: IgorBin.h:28
int ReadWave(CP_FILE_REF fr, int *typePtr, long *npntsPtr, long *ndimptr, double *sfa, double *sfb, void **waveDataPtrPtr, char **name)
Definition: ReadWave.cpp:295
std::string toLowerCase(const std::string &)
Converts uppercase to lowercase letters.
A table column containing categorical values.
A table column containing numerical values formatted as dates and times.
This class extends the std::vector for endlessness.
Definition: structures.hpp:838
This class implements the basic input/ output file system and provides functionalities to work with f...
Definition: filesystem.hpp:92
std::vector< std::string > getFileParts(const std::string &sFilePath) const
This member function separates all path parts into single strings: the drive letter,...
Definition: filesystem.cpp:566
void initializeFromKernel()
Member function to remote-initialize the class from the kernel. Cannot be used during kernel start-up...
Definition: filesystem.cpp:750
This class handles the internal language system and returns the language strings of the selected lang...
Definition: language.hpp:38
std::string get(const std::string &sMessage, const std::vector< std::string > &vTokens) const
This member function returns the language string for the passed language identifier and replaces all ...
Definition: language.cpp:292
A table column containing logical values.
CacheFile(const std::string &filename)
Definition: file.cpp:1630
void readCacheHeader()
This member function will read the cache file header and ensure that the version of the file is not n...
Definition: file.cpp:1732
void reset()
This member function will reset the string information and the internal storage. This is used before ...
Definition: file.cpp:1661
void writeSome()
This member function will write the current contents in the internal storage to the target file....
Definition: file.cpp:1704
size_t nIndexPos
Definition: file.hpp:1579
std::vector< size_t > vFileIndex
Definition: file.hpp:1578
void readSome()
This member function will read the next table, which is availale in the cache file,...
Definition: file.cpp:1679
void writeCacheHeader()
This member function will write the standard cache file header to the cache file.
Definition: file.cpp:1784
virtual ~CacheFile()
This destructor will write the offsets for the different tables to the file before the file stream wi...
Definition: file.cpp:1641
This class resembles the CASSYLab *.labx file format, which is based upon XML. Only reading from this...
Definition: file.hpp:1655
void readFile()
This member function will read the contents of the associated LABX file to the internal storage.
Definition: file.cpp:1835
CassyLabx(const std::string &filename)
Definition: file.cpp:1815
virtual ~CassyLabx()
Definition: file.cpp:1821
double extractValueFromTag(const std::string &sTag)
This simple member function extracts the numerical value of the XML tag string.
Definition: file.cpp:1963
This class resembles a comma separated value file format (*.csv). The algorithm may detect the separa...
Definition: file.hpp:1686
char findSeparator(const std::vector< std::string > &vTextData)
This member function determines the separator character used for the current file name....
Definition: file.cpp:2199
virtual ~CommaSeparatedValues()
Definition: file.cpp:1979
void readFile()
This member function is used to read the target file to memory.
Definition: file.cpp:1992
void writeFile()
This member function is used to write the contents in the internal storage to the target file.
Definition: file.cpp:2147
void countColumns(const std::vector< std::string > &vTextData, char &cSep)
This member function determines the number of columns available in the current file and alters the se...
Definition: file.cpp:2284
CommaSeparatedValues(const std::string &filename)
Definition: file.cpp:1973
Template class representing a generic file. This class may be specified for the main data type contai...
Definition: file.hpp:68
void writeStringField(const std::string &sString)
This method may be used to write a string to file in binary mode.
Definition: file.hpp:591
unsigned short nPrecFields
Definition: file.hpp:77
void writeNumBlock(T *data, long long int size)
This method template may be used to write a block of data of the selected type to the file in binary ...
Definition: file.hpp:608
void writeNumField(T num)
This method template can be used to write a numeric value to file in binary mode.
Definition: file.hpp:578
std::string * readStringBlock(long long int &size)
This method can be used for reading a block of string data to memory in binary mode.
Definition: file.hpp:476
void writeStringBlock(std::string *data, long long int size)
This method may be used to write a block of strings into the file in binary mode.
Definition: file.hpp:646
std::string getTableName()
Returns the table name referenced in the file. Will default to the file name with non-alnum character...
Definition: file.hpp:977
bool isNumeric(const std::string &sString)
This method may be used to determine, whether a string contains only numeric data.
Definition: file.hpp:779
size_t tellg()
Wrapper for fstream::tellg()
Definition: file.hpp:903
size_t tellp()
Wrapper for fstream::tellp()
Definition: file.hpp:914
void seekp(size_t pos)
Wrapper for fstream::seekp() with start from the beginning of the stream.
Definition: file.hpp:940
long long int nRows
Definition: file.hpp:75
void copyArray(T *from, T *to, long long int nElements)
This method template may be used to copy arrays of data of the selected type. Both source and target ...
Definition: file.hpp:761
std::pair< size_t, size_t > calculateCellExtents(const std::string &sContents)
This method calculates the extents of the passed string, if it is used as a table column headlines....
Definition: file.hpp:220
std::string sFileName
Definition: file.hpp:72
std::string getZipFileItem(const std::string &filename)
This method may be used to get the contents of an embedded file in a zipfile and return the contents ...
Definition: file.hpp:384
void replaceTabSign(std::string &_sToReplace, bool bAddPlaceholders=false)
This method replaces tabulator characters with whitespaces to simplify the column determination (the ...
Definition: file.hpp:157
std::string getLineFromHead(long long int nCol, size_t nLineNumber)
This method gets the selected line number from the table column headline in the selected column....
Definition: file.hpp:277
std::string sTableName
Definition: file.hpp:73
void clearStorage()
This method cleares the internal storage. This method is called by the destructor automatically.
Definition: file.hpp:687
std::fstream fFileStream
Definition: file.hpp:70
bool is_open()
Wrapper for fstream::is_open()
Definition: file.hpp:868
std::string sComment
Definition: file.hpp:74
TableColumnArray * fileData
Definition: file.hpp:85
std::vector< std::string > tokenize(std::string sString, const std::string &sSeparators, bool skipEmptyTokens=false)
This method may be used to separater a line into multiple tokens using a set of separator characters....
Definition: file.hpp:544
std::string readStringField()
This mehtod can be used to read a string field from the file in binary mode.
Definition: file.hpp:352
void open(std::ios::openmode mode)
This method has to be used to open the target file in stream mode. If the file cannot be opened,...
Definition: file.hpp:96
void createStorage()
This method prepares the internal storage, so that it may contain the read data. This method is only ...
Definition: file.hpp:668
long long int nCols
Definition: file.hpp:76
void assign(const GenericFile &file)
This method is used by the assignment operator and the copy constructor to copy the contents of the p...
Definition: file.hpp:796
std::vector< std::string > readTextFile(bool stripEmptyLines)
This method may be used to read the file in text mode and to obtain the data as a vector.
Definition: file.hpp:507
void seekg(size_t pos)
Wrapper for fstream::seekg() with start from the beginning of the stream.
Definition: file.hpp:927
void stripTrailingSpaces(std::string &_sToStrip)
This method strips trailing spaces from the passed string.
Definition: file.hpp:117
This class resembles an Igor binary wave file format (*.ibw). The data is read by the WaveMetrics imp...
Definition: file.hpp:1881
IgorBinaryWave & operator=(const IgorBinaryWave &file)
This is an overload for the assignment operator of the GenericFile class.
Definition: file.cpp:4557
void readFile()
This member function is used to read the contents of the IBW file into the internal storage....
Definition: file.cpp:4339
virtual ~IgorBinaryWave()
Definition: file.cpp:4324
IgorBinaryWave(const std::string &filename)
Definition: file.cpp:4305
This class resembles a JCAMP-DX file format (*.jcm, *.jdx, *.dx). The data in this format may be hash...
Definition: file.hpp:1754
size_t readTable(std::vector< std::string > &vFileContents, size_t nTableStart, MetaData)
Reads a single table from the currently opened JCAMP-DX file.
Definition: file.cpp:2893
std::vector< double > parseLine(const std::string &sLine)
This member function parses the current data line into numerical values by decoding the JCAMP-DX enco...
Definition: file.cpp:3167
virtual ~JcampDX()
Definition: file.cpp:2669
void readFile()
This member function is used to read the conents of the JCAMP-DX file to the internal storage.
Definition: file.cpp:2715
void parseLabel(std::string &sLine)
This member function parses JCAMP-DX labels by removing whitespaces, minus characters and underscores...
Definition: file.cpp:3128
JcampDX(const std::string &filename)
Definition: file.cpp:2663
This class resembles a LaTeX table. This class formats the data into this format using some heuristic...
Definition: file.hpp:1720
LaTeXTable(const std::string &filename)
Definition: file.cpp:2326
std::string replaceNonASCII(const std::string &sText)
This member function replaces all non- ASCII characters into their corresponding LaTeX entities.
Definition: file.cpp:2567
std::string formatNumber(const mu::value_type &number)
This member function formats a complex as LaTeX number string.
Definition: file.cpp:2629
void writeFile()
This member function is used to write the contents of the internal storage to the file.
Definition: file.cpp:2346
void writeHeader()
This member function writes the legal header to the file.
Definition: file.cpp:2470
void writeTableHeads()
This member function writes the table column heads to the file. The number of lines needed for the he...
Definition: file.cpp:2500
size_t countHeadLines()
This member function calculates the number of lines needed for the complete table column heads.
Definition: file.cpp:2536
virtual ~LaTeXTable()
Definition: file.cpp:2332
This class resembles the binary NumeRe data file format. The data is red and written in binary mode u...
Definition: file.hpp:1471
void writeDummyHeader()
This member function will write the dummy header, which is readable in older versions of NumeRe....
Definition: file.cpp:920
std::string getVersionString()
This simple member function returns the version string associated with the current file type.
Definition: file.cpp:1620
const short fileSpecVersionMinor
Definition: file.hpp:1479
NumeReDataFile(const std::string &filename)
Definition: file.cpp:827
void readColumnV4(TblColPtr &col)
Reads a single column from file in v4 format.
Definition: file.cpp:1342
long int versionBuild
Definition: file.hpp:1477
void * readGenericField(std::string &type, long long int &size)
This member function will read a generic field from the header (the three fields, which can be used i...
Definition: file.cpp:1503
void writeHeader()
This member function writest the new standard header for NDAT files. It includes a dummy section,...
Definition: file.cpp:871
void skipDummyHeader()
This function jumps over the dummy section in the new file format, because it does not conatin any va...
Definition: file.cpp:1169
void readFile()
This member function will read the contents of the target file.
Definition: file.cpp:1190
__time64_t timeStamp
Definition: file.hpp:1474
void deleteGenericData(void *data, const std::string &type)
This member function will delete the data array obtained from the generic fields but convert them int...
Definition: file.cpp:1566
const short fileSpecVersionMajor
Definition: file.hpp:1478
virtual ~NumeReDataFile()
Definition: file.cpp:855
void readLegacyFormat()
This member function reads the data section of the target file in legacy format. The function readHea...
Definition: file.cpp:1413
void writeFile()
This member function will write the data in the internal storage into the target file.
Definition: file.cpp:942
void writeColumn(const TblColPtr &col)
Writes a single column to the file.
Definition: file.cpp:981
void readHeader()
This member function will read the header in the selected file. It will automatically detect,...
Definition: file.cpp:1060
void readColumn(TblColPtr &col)
Reads a single column from file.
Definition: file.cpp:1278
NumeReDataFile & operator=(NumeReDataFile &file)
This member function is an overload for the assignment operator. It extends the already available ass...
Definition: file.cpp:1598
long int versionMajor
Definition: file.hpp:1475
long int versionMinor
Definition: file.hpp:1476
This class resembles an OpenDocument spreadsheet (*.ods), which is based upon a zipped XML file....
Definition: file.hpp:1789
std::string expandLine(const std::string &sLine)
This member function is used by the readFile() member function to expand the XML- based table row str...
Definition: file.cpp:3613
void readFile()
This member function is used to read the targed file into the internal storage. ODS is a ZIP file con...
Definition: file.cpp:3350
OpenDocumentSpreadSheet(const std::string &filename)
Definition: file.cpp:3329
This class resembles an arbitrary text data file, which is formatted in a table-like manner....
Definition: file.hpp:1434
void writeTableHeads(const std::vector< size_t > &vColumnWidth, size_t nNumberOfLines)
This member function is used to write the table heads into the target file.
Definition: file.cpp:293
void readFile()
This method reads the data in the referenced text file to memory.
Definition: file.cpp:115
virtual ~TextDataFile()
Definition: file.cpp:102
TextDataFile(const std::string &filename)
Definition: file.cpp:96
void writeHeader()
This member function writes the header lines or the text files.
Definition: file.cpp:263
void writeTableContents(const std::vector< size_t > &vColumnWidth)
This member function is used to write the data in memory to the target text file.
Definition: file.cpp:326
std::vector< size_t > calculateColumnWidths(size_t &nNumberOfLines)
This member function calculates the widths of the columns and also determines the number of lines nee...
Definition: file.cpp:795
void addSeparator(const std::vector< size_t > &vColumnWidth)
This member function draws a separator based upon the overall width of the columns.
Definition: file.cpp:362
void writeFile()
This method writes the data in memory to the referenced text file.
Definition: file.cpp:234
void decodeTableHeads(std::vector< std::string > &vFileContents, long long int nComment)
This member function decodes the table heads in the text file and stores them in memory.
Definition: file.cpp:390
This class resembles an Excel (97) workbook (*.xls), which is composed out of a compound file....
Definition: file.hpp:1819
virtual ~XLSSpreadSheet()
Definition: file.cpp:3709
void writeFile()
This member function is used to write the data in the internal storage to the target XLS spreadsheet.
Definition: file.cpp:3911
XLSSpreadSheet(const std::string &filename)
Definition: file.cpp:3703
void readFile()
This member function is used to read the data from the XLS spreadsheet ino the internal storage.
Definition: file.cpp:3723
This class resembles an Excel (2003) spreadsheet (*.xlsx), which is based upon a zipped XML file....
Definition: file.hpp:1850
XLSXSpreadSheet(const std::string &filename)
Definition: file.cpp:3978
virtual ~XLSXSpreadSheet()
Definition: file.cpp:3984
void evalIndices(const std::string &sIndices, int &nLine, int &nCol)
This member function converts the usual Excel indices into numerical ones.
Definition: file.cpp:4272
void readFile()
This member function is used to read the data from the XLSX spreadsheet into the internal storage....
Definition: file.cpp:3999
This class implements a Zygo MetroPro binary dat file. The data is read by accessing the ZygoLib.
Definition: file.hpp:1927
void readFile()
This member function is used to read the contents of the Zygo Dat file into the internal storage....
Definition: file.cpp:4604
virtual ~ZygoDat()
Definition: file.cpp:4589
ZygoDat(const std::string &filename)
Definition: file.cpp:4570
ZygoDat & operator=(const ZygoDat &file)
This is an overload for the assignment operator of the GenericFile class.
Definition: file.cpp:4690
static void issueWarning(std::string sWarningMessage)
This static function may be used to issue a warning to the user. The warning will be printed by the t...
Definition: kernel.cpp:2833
A table column containing only strings as values.
Common exception class for all exceptions thrown in NumeRe.
Definition: error.hpp:32
@ CANNOT_READ_FILE
Definition: error.hpp:75
@ COL_COUNTS_DOESNT_MATCH
INSERT HERE.
Definition: error.hpp:91
@ DATAFILE_NOT_EXIST
INSERT HERE.
Definition: error.hpp:94
@ INSUFFICIENT_NUMERE_VERSION
Definition: error.hpp:122
@ FILE_IS_EMPTY
Definition: error.hpp:104
static size_t invalid_position
Definition: error.hpp:235
A table column containing only numerical values.
This class abstracts all the index logics, i.e. the logical differences between single indices and in...
Definition: structures.hpp:42
void SetDouble(double val)
Set content of current Excel cell to a double.
int Type() const
Get type of value stored in current Excel cell. Returns one of the above enums.
const char * GetString() const
Get an ANSI string. Returns 0 if cell does not contain an ANSI string.
void EraseContents()
Erase the content of current Excel cell. Set type to UNDEFINED.
const wchar_t * GetWString() const
Get an Unicode string. Returns 0 if cell does not contain an Unicode string.
double GetDouble() const
Get a double value. Returns 0.0 if cell does not contain a double.
int GetInteger() const
Get an integer value. Returns 0 if cell does not contain an integer.
void SetString(const char *str)
Set content of current Excel cell to an ANSI string.
void New(int sheets=3)
Create a new Excel workbook with a given number of spreadsheets (Minimum 1).
BasicExcelWorksheet * GetWorksheet(size_t sheetIndex)
Get a pointer to an Excel worksheet at the given index. Index starts from 0. Returns 0 if index is in...
size_t GetTotalWorkSheets()
Total number of Excel worksheets in current Excel workbook.
bool Load(const char *filename)
Load an Excel workbook from a file.
bool SaveAs(const char *filename)
Save current Excel workbook to a file.
bool RenameWorksheet(size_t sheetIndex, const char *to)
Rename an Excel worksheet at the given index to the given ANSI name. Index starts from 0....
size_t GetTotalCols()
Total number of columns in current Excel worksheet.
BasicExcelCell * Cell(size_t row, size_t col)
Return a pointer to an Excel cell. row and col starts from 0. Returns 0 if row exceeds 65535 or col e...
size_t GetTotalRows()
Total number of rows in current Excel worksheet.
XMLError Parse(const char *xml, size_t nBytes=static_cast< size_t >(-1))
Definition: tinyxml2.cpp:2415
XMLError ErrorID() const
Return the errorID.
Definition: tinyxml2.h:1885
const char * GetText() const
Definition: tinyxml2.cpp:1656
const char * Attribute(const char *name, const char *value=0) const
Definition: tinyxml2.cpp:1595
XMLError QueryIntText(int *ival) const
Definition: tinyxml2.cpp:1740
const char * Value() const
Definition: tinyxml2.cpp:817
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:696
const XMLElement * NextSiblingElement(const char *name=0) const
Get the next (right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:1018
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:994
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:692
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:769
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
Definition: tinyxml2.h:821
#define DEFAULT_PRECISION
Definition: file.cpp:32
Language _lang
Definition: kernel.cpp:39
static const long MINOR
Definition: version.h:18
static const long BUILD
Definition: version.h:19
static const char DATE[]
Definition: version.h:7
static const long MAJOR
Definition: version.h:17
static const char MONTH[]
Definition: version.h:8
static const char YEAR[]
Definition: version.h:9
GenericFile * getFileByType(const string &filename)
This function determines the correct class to be used for the filename passed to this function....
Definition: file.cpp:45
CONSTCD11 std::enable_if<!std::chrono::treat_as_floating_point< T >::value, T >::type trunc(T t) NOEXCEPT
Definition: date.h:1113
CONSTCD11 std::chrono::duration< Rep, Period > abs(std::chrono::duration< Rep, Period > d)
Definition: date.h:1317
MUP_BASETYPE value_type
The numeric datatype used by the parser.
Definition: muParserDef.h:251
CONSTDATA solar_hijri::month sha
Definition: solar_hijri.h:1388
#define min(a, b)
Definition: resampler.cpp:34
#define max(a, b)
Definition: resampler.cpp:30
void StripSpaces(std::string &)
Removes leading and trailing white spaces and tabulator characters.
int StrToInt(const std::string &)
Converts a string into an integer.
double StrToDb(const std::string &sString)
Converts a string into a double.
bool isConvertible(const std::string &sStr, ConvertibleType type)
This function checks, whether a string can be converted to the selected ConvertibleType.
std::string utf8parser(const std::string &sString)
Transforms a UTF8 encoded string into a standard ASCII string in the internal code page representatio...
std::string toUpperCase(const std::string &sLowerCase)
Converts lowercase letters to uppercase ones.
std::string wcstombs(const std::wstring &wStr)
This function is a wrapper for the usual wcstombs function, which can handle wstrings.
void replaceAll(std::string &sToModify, const char *sToRep, const char *sNewValue, size_t nStart, size_t nEnd)
This function replaces all occurences of the string sToRep in the string sToModify with the new value...
std::string getTimeStamp(bool bGetStamp)
This function simple returns the current time as a default timestamp.
@ CONVTYPE_VALUE
Definition: stringtools.hpp:44
Structure for storing the JCAMP-DX meta data.
Definition: file.cpp:2681
std::string m_symbol
Definition: file.cpp:2701
static std::string getDefaultColumnHead(size_t colNo)
Creates a default column headline for a column, which can be used without an instance of this class.
std::string toString(int)
Converts an integer to a string without the Settings bloat.
std::unique_ptr< TableColumn > TblColPtr
Typedef for simplifying the usage of a smart pointer in combination with a TableColumn instance.
std::vector< TblColPtr > TableColumnArray
This typedef represents the actual table, which is implemented using a std::vector.
string getArgAtPos(const string &sCmd, unsigned int nPos, int extraction)
Extracts a options value at the selected position and applies automatic parsing, if necessary.
Definition: tools.cpp:1598
EndlessVector< StringView > getAllArguments(StringView sArgList)
Splits up the complete argument list and returns them as an EndlessVector.
Definition: tools.cpp:2346