Line data Source code
1 :
2 : /*
3 : * ALMA - Atacama Large Millimeter Array
4 : * (c) European Southern Observatory, 2002
5 : * (c) Associated Universities Inc., 2002
6 : * Copyright by ESO (in the framework of the ALMA collaboration),
7 : * Copyright by AUI (in the framework of the ALMA collaboration),
8 : * All rights reserved.
9 : *
10 : * This library is free software; you can redistribute it and/or
11 : * modify it under the terms of the GNU Lesser General Public
12 : * License as published by the Free software Foundation; either
13 : * version 2.1 of the License, or (at your option) any later version.
14 : *
15 : * This library is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY, without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 : * Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; if not, write to the Free Software
22 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
23 : * MA 02111-1307 USA
24 : *
25 : * Warning!
26 : * --------------------------------------------------------------------
27 : * | This is generated code! Do not modify this file. |
28 : * | If you do, all changes will be lost when the file is re-generated. |
29 : * --------------------------------------------------------------------
30 : *
31 : * File SysCalTable.cpp
32 : */
33 : #include <alma/ASDM/ConversionException.h>
34 : #include <alma/ASDM/DuplicateKey.h>
35 : #include <alma/ASDM/OutOfBoundsException.h>
36 :
37 : using asdm::ConversionException;
38 : using asdm::DuplicateKey;
39 : using asdm::OutOfBoundsException;
40 :
41 : #include <alma/ASDM/ASDM.h>
42 : #include <alma/ASDM/SysCalTable.h>
43 : #include <alma/ASDM/SysCalRow.h>
44 : #include <alma/ASDM/Parser.h>
45 :
46 : using asdm::ASDM;
47 : using asdm::SysCalTable;
48 : using asdm::SysCalRow;
49 : using asdm::Parser;
50 :
51 : #include <iostream>
52 : #include <fstream>
53 : #include <iterator>
54 : #include <sstream>
55 : #include <set>
56 : #include <algorithm>
57 : using namespace std;
58 :
59 : #include <alma/ASDM/Misc.h>
60 : using namespace asdm;
61 :
62 : #include <libxml/parser.h>
63 : #include <libxml/tree.h>
64 :
65 : #ifndef WITHOUT_BOOST
66 : #include "boost/filesystem/operations.hpp"
67 : #include <boost/algorithm/string.hpp>
68 : #else
69 : #include <sys/stat.h>
70 : #endif
71 :
72 : namespace asdm {
73 : // The name of the entity we will store in this table.
74 : static string entityNameOfSysCal = "SysCal";
75 :
76 : // An array of string containing the names of the columns of this table.
77 : // The array is filled in the order : key, required value, optional value.
78 : //
79 : static string attributesNamesOfSysCal_a[] = {
80 :
81 : "antennaId"
82 : ,
83 : "spectralWindowId"
84 : ,
85 : "timeInterval"
86 : ,
87 : "feedId"
88 :
89 :
90 : , "numReceptor"
91 :
92 : , "numChan"
93 :
94 :
95 : , "tcalFlag"
96 :
97 : , "tcalSpectrum"
98 :
99 : , "trxFlag"
100 :
101 : , "trxSpectrum"
102 :
103 : , "tskyFlag"
104 :
105 : , "tskySpectrum"
106 :
107 : , "tsysFlag"
108 :
109 : , "tsysSpectrum"
110 :
111 : , "tantFlag"
112 :
113 : , "tantSpectrum"
114 :
115 : , "tantTsysFlag"
116 :
117 : , "tantTsysSpectrum"
118 :
119 : , "phaseDiffFlag"
120 :
121 : , "phaseDiffSpectrum"
122 :
123 : };
124 :
125 : // A vector of string whose content is a copy of the strings in the array above.
126 : //
127 : static vector<string> attributesNamesOfSysCal_v (attributesNamesOfSysCal_a, attributesNamesOfSysCal_a + sizeof(attributesNamesOfSysCal_a) / sizeof(attributesNamesOfSysCal_a[0]));
128 :
129 : // An array of string containing the names of the columns of this table.
130 : // The array is filled in the order where the names would be read by default in the XML header of a file containing
131 : // the table exported in binary mode.
132 : //
133 : static string attributesNamesInBinOfSysCal_a[] = {
134 :
135 : "antennaId" , "spectralWindowId" , "timeInterval" , "feedId" , "numReceptor" , "numChan"
136 : ,
137 : "tcalFlag" , "tcalSpectrum" , "trxFlag" , "trxSpectrum" , "tskyFlag" , "tskySpectrum" , "tsysFlag" , "tsysSpectrum" , "tantFlag" , "tantSpectrum" , "tantTsysFlag" , "tantTsysSpectrum" , "phaseDiffFlag" , "phaseDiffSpectrum"
138 :
139 : };
140 :
141 : // A vector of string whose content is a copy of the strings in the array above.
142 : //
143 : static vector<string> attributesNamesInBinOfSysCal_v(attributesNamesInBinOfSysCal_a, attributesNamesInBinOfSysCal_a + sizeof(attributesNamesInBinOfSysCal_a) / sizeof(attributesNamesInBinOfSysCal_a[0]));
144 :
145 :
146 : // The array of attributes (or column) names that make up key key.
147 : //
148 : string keyOfSysCal_a[] = {
149 :
150 : "antennaId"
151 : ,
152 : "spectralWindowId"
153 : ,
154 : "timeInterval"
155 : ,
156 : "feedId"
157 :
158 : };
159 :
160 : // A vector of strings which are copies of those stored in the array above.
161 : vector<string> keyOfSysCal_v(keyOfSysCal_a, keyOfSysCal_a + sizeof(keyOfSysCal_a) / sizeof(keyOfSysCal_a[0]));
162 :
163 : /**
164 : * Return the list of field names that make up key key
165 : * as a const reference to a vector of strings.
166 : */
167 0 : const vector<string>& SysCalTable::getKeyName() {
168 0 : return keyOfSysCal_v;
169 : }
170 :
171 :
172 0 : SysCalTable::SysCalTable(ASDM &c) : container(c) {
173 :
174 : // Define a default entity.
175 0 : entity.setEntityId(EntityId("uid://X0/X0/X0"));
176 0 : entity.setEntityIdEncrypted("na");
177 0 : entity.setEntityTypeName("SysCalTable");
178 0 : entity.setEntityVersion("1");
179 0 : entity.setInstanceVersion("1");
180 :
181 : // Archive XML
182 0 : archiveAsBin = true;
183 :
184 : // File XML
185 0 : fileAsBin = true;
186 :
187 : // By default the table is considered as present in memory
188 0 : presentInMemory = true;
189 :
190 : // By default there is no load in progress
191 0 : loadInProgress = false;
192 0 : }
193 :
194 : /**
195 : * A destructor for SysCalTable.
196 : */
197 0 : SysCalTable::~SysCalTable() {
198 0 : for (unsigned int i = 0; i < privateRows.size(); i++)
199 0 : delete(privateRows.at(i));
200 0 : }
201 :
202 : /**
203 : * Container to which this table belongs.
204 : */
205 0 : ASDM &SysCalTable::getContainer() const {
206 0 : return container;
207 : }
208 :
209 : /**
210 : * Return the number of rows in the table.
211 : */
212 0 : unsigned int SysCalTable::size() const {
213 0 : if (presentInMemory)
214 0 : return privateRows.size();
215 : else
216 0 : return declaredSize;
217 : }
218 :
219 : /**
220 : * Return the name of this table.
221 : */
222 0 : string SysCalTable::getName() const {
223 0 : return entityNameOfSysCal;
224 : }
225 :
226 : /**
227 : * Return the name of this table.
228 : */
229 0 : string SysCalTable::name() {
230 0 : return entityNameOfSysCal;
231 : }
232 :
233 : /**
234 : * Return the the names of the attributes (or columns) of this table.
235 : */
236 0 : const vector<string>& SysCalTable::getAttributesNames() { return attributesNamesOfSysCal_v; }
237 :
238 : /**
239 : * Return the the names of the attributes (or columns) of this table as they appear by default
240 : * in an binary export of this table.
241 : */
242 0 : const vector<string>& SysCalTable::defaultAttributesNamesInBin() { return attributesNamesInBinOfSysCal_v; }
243 :
244 : /**
245 : * Return this table's Entity.
246 : */
247 0 : Entity SysCalTable::getEntity() const {
248 0 : return entity;
249 : }
250 :
251 : /**
252 : * Set this table's Entity.
253 : */
254 0 : void SysCalTable::setEntity(Entity e) {
255 0 : this->entity = e;
256 0 : }
257 :
258 : //
259 : // ====> Row creation.
260 : //
261 :
262 : /**
263 : * Create a new row.
264 : */
265 0 : SysCalRow *SysCalTable::newRow() {
266 0 : return new SysCalRow (*this);
267 : }
268 :
269 :
270 : /**
271 : * Create a new row initialized to the specified values.
272 : * @return a pointer on the created and initialized row.
273 :
274 : * @param antennaId
275 :
276 : * @param spectralWindowId
277 :
278 : * @param timeInterval
279 :
280 : * @param feedId
281 :
282 : * @param numReceptor
283 :
284 : * @param numChan
285 :
286 : */
287 0 : SysCalRow* SysCalTable::newRow(Tag antennaId, Tag spectralWindowId, ArrayTimeInterval timeInterval, int feedId, int numReceptor, int numChan){
288 0 : SysCalRow *row = new SysCalRow(*this);
289 :
290 0 : row->setAntennaId(antennaId);
291 :
292 0 : row->setSpectralWindowId(spectralWindowId);
293 :
294 0 : row->setTimeInterval(timeInterval);
295 :
296 0 : row->setFeedId(feedId);
297 :
298 0 : row->setNumReceptor(numReceptor);
299 :
300 0 : row->setNumChan(numChan);
301 :
302 0 : return row;
303 : }
304 :
305 :
306 :
307 0 : SysCalRow* SysCalTable::newRow(SysCalRow* row) {
308 0 : return new SysCalRow(*this, row);
309 : }
310 :
311 : //
312 : // Append a row to its table.
313 : //
314 :
315 :
316 :
317 :
318 :
319 : /**
320 : * Returns a string built by concatenating the ascii representation of the
321 : * parameters values suffixed with a "_" character.
322 : */
323 0 : string SysCalTable::Key(Tag antennaId, Tag spectralWindowId, int feedId) {
324 0 : ostringstream ostrstr;
325 : ostrstr
326 :
327 0 : << antennaId.toString() << "_"
328 :
329 0 : << spectralWindowId.toString() << "_"
330 :
331 0 : << feedId << "_"
332 :
333 : ;
334 0 : return ostrstr.str();
335 0 : }
336 :
337 :
338 :
339 0 : SysCalRow* SysCalTable::add(SysCalRow* x) {
340 0 : ArrayTime startTime = x->getTimeInterval().getStart();
341 :
342 : /*
343 : * Is there already a context for this combination of not temporal
344 : * attributes ?
345 : */
346 : string k = Key(
347 0 : x->getAntennaId()
348 : ,
349 0 : x->getSpectralWindowId()
350 : ,
351 : x->getFeedId()
352 0 : );
353 :
354 0 : if (context.find(k) == context.end()) {
355 : // There is not yet a context ...
356 : // Create and initialize an entry in the context map for this combination....
357 0 : TIME_ROWS v;
358 0 : context[k] = v;
359 0 : }
360 :
361 0 : return insertByStartTime(x, context[k]);
362 0 : }
363 :
364 :
365 :
366 :
367 0 : void SysCalTable::addWithoutCheckingUnique(SysCalRow * x) {
368 0 : SysCalRow * dummy = checkAndAdd(x, true); // We require the check for uniqueness to be skipped.
369 : // by passing true in the second parameter
370 : // whose value by default is false.
371 : // this statement is never executed, but it hides the unused return value from the compiler to silence that warning.
372 : if (false) cout << (unsigned long long) dummy;
373 0 : }
374 :
375 :
376 :
377 :
378 : //
379 : // A private method to append a row to its table, used by input conversion
380 : // methods, with row uniqueness.
381 : //
382 :
383 :
384 :
385 :
386 :
387 :
388 :
389 :
390 :
391 0 : SysCalRow* SysCalTable::checkAndAdd(SysCalRow* x, bool /* skipCheckUniqueness */ ) {
392 : string keystr = Key(
393 0 : x->getAntennaId()
394 : ,
395 0 : x->getSpectralWindowId()
396 : ,
397 : x->getFeedId()
398 0 : );
399 0 : if (context.find(keystr) == context.end()) {
400 0 : vector<SysCalRow *> v;
401 0 : context[keystr] = v;
402 0 : }
403 :
404 0 : vector<SysCalRow*>& found = context.find(keystr)->second;
405 0 : return insertByStartTime(x, found);
406 0 : }
407 :
408 :
409 :
410 :
411 :
412 :
413 : //
414 : // A private method to brutally append a row to its table, without checking for row uniqueness.
415 : //
416 :
417 0 : void SysCalTable::append(SysCalRow *x) {
418 0 : privateRows.push_back(x);
419 0 : x->isAdded(true);
420 0 : }
421 :
422 :
423 :
424 :
425 :
426 0 : vector<SysCalRow *> SysCalTable::get() {
427 0 : checkPresenceInMemory();
428 0 : return privateRows;
429 : }
430 :
431 0 : const vector<SysCalRow *>& SysCalTable::get() const {
432 0 : const_cast<SysCalTable&>(*this).checkPresenceInMemory();
433 0 : return privateRows;
434 : }
435 :
436 :
437 :
438 :
439 :
440 :
441 :
442 :
443 :
444 :
445 0 : vector<SysCalRow *> *SysCalTable::getByContext(Tag antennaId, Tag spectralWindowId, int feedId) {
446 : //if (getContainer().checkRowUniqueness() == false)
447 : //throw IllegalAccessException ("The method 'getByContext' can't be called because the dataset has been built without checking the row uniqueness.", "SysCalTable");
448 :
449 0 : checkPresenceInMemory();
450 0 : string k = Key(antennaId, spectralWindowId, feedId);
451 :
452 0 : if (context.find(k) == context.end()) return 0;
453 0 : else return &(context[k]);
454 0 : }
455 :
456 :
457 :
458 :
459 :
460 :
461 :
462 :
463 :
464 :
465 : /*
466 : ** Returns a SysCalRow* given a key.
467 : ** @return a pointer to the row having the key whose values are passed as parameters, or 0 if
468 : ** no row exists for that key.
469 : **
470 : */
471 :
472 :
473 0 : SysCalRow* SysCalTable::getRowByKey(Tag antennaId, Tag spectralWindowId, ArrayTimeInterval timeInterval, int feedId) {
474 0 : checkPresenceInMemory();
475 0 : string keystr = Key(antennaId, spectralWindowId, feedId);
476 0 : vector<SysCalRow *> row;
477 :
478 0 : if ( context.find(keystr) == context.end()) return 0;
479 :
480 0 : row = context[keystr];
481 :
482 : // Is the vector empty...impossible in principle !
483 0 : if (row.size() == 0) return 0;
484 :
485 : // Only one element in the vector
486 0 : if (row.size() == 1) {
487 0 : SysCalRow* r = row.at(0);
488 0 : if ( r->getTimeInterval().contains(timeInterval.getStart()))
489 0 : return r;
490 : else
491 0 : return 0;
492 : }
493 :
494 : // Optimizations
495 0 : SysCalRow* last = row.at(row.size()-1);
496 0 : if (timeInterval.getStart().get() >= (last->getTimeInterval().getStart().get()+last->getTimeInterval().getDuration().get())) return 0;
497 :
498 0 : SysCalRow* first = row.at(0);
499 0 : if (timeInterval.getStart().get() < first->getTimeInterval().getStart().get()) return 0;
500 :
501 :
502 : // More than one row
503 : // Let's use a dichotomy method for the general case..
504 0 : int k0 = 0;
505 0 : int k1 = row.size() - 1;
506 0 : SysCalRow* r = 0;
507 0 : while (k0!=k1) {
508 :
509 : // Is the start time contained in the time interval of row #k0
510 0 : r = row.at(k0);
511 0 : if (r->getTimeInterval().contains(timeInterval.getStart())) return r;
512 :
513 : // Is the start contained in the time interval of row #k1
514 0 : r = row.at(k1);
515 0 : if (r->getTimeInterval().contains(timeInterval.getStart())) return r;
516 :
517 : // Are the rows #k0 and #k1 consecutive
518 : // Then we know for sure that there is no row containing the start of timeInterval
519 0 : if (k1==(k0+1)) return 0;
520 :
521 : // Proceed to the next step of dichotomy.
522 0 : r = row.at((k0+k1)/2);
523 0 : if ( timeInterval.getStart().get() <= r->getTimeInterval().getStart().get())
524 0 : k1 = (k0 + k1) / 2;
525 : else
526 0 : k0 = (k0 + k1) / 2;
527 : }
528 0 : return 0;
529 0 : }
530 :
531 :
532 :
533 :
534 :
535 :
536 :
537 :
538 :
539 : #ifndef WITHOUT_ACS
540 : using asdmIDL::SysCalTableIDL;
541 : #endif
542 :
543 : #ifndef WITHOUT_ACS
544 : // Conversion Methods
545 :
546 : SysCalTableIDL *SysCalTable::toIDL() {
547 : SysCalTableIDL *x = new SysCalTableIDL ();
548 : unsigned int nrow = size();
549 : x->row.length(nrow);
550 : vector<SysCalRow*> v = get();
551 : for (unsigned int i = 0; i < nrow; ++i) {
552 : //x->row[i] = *(v[i]->toIDL());
553 : v[i]->toIDL(x->row[i]);
554 : }
555 : return x;
556 : }
557 :
558 : void SysCalTable::toIDL(asdmIDL::SysCalTableIDL& x) const {
559 : unsigned int nrow = size();
560 : x.row.length(nrow);
561 : vector<SysCalRow*> v = get();
562 : for (unsigned int i = 0; i < nrow; ++i) {
563 : v[i]->toIDL(x.row[i]);
564 : }
565 : }
566 : #endif
567 :
568 : #ifndef WITHOUT_ACS
569 : void SysCalTable::fromIDL(SysCalTableIDL x) {
570 : unsigned int nrow = x.row.length();
571 : for (unsigned int i = 0; i < nrow; ++i) {
572 : SysCalRow *tmp = newRow();
573 : tmp->setFromIDL(x.row[i]);
574 : // checkAndAdd(tmp);
575 : add(tmp);
576 : }
577 : }
578 : #endif
579 :
580 :
581 0 : string SysCalTable::toXML() {
582 0 : string buf;
583 :
584 0 : buf.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?> ");
585 0 : buf.append("<SysCalTable xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:syscal=\"http://Alma/XASDM/SysCalTable\" xsi:schemaLocation=\"http://Alma/XASDM/SysCalTable http://almaobservatory.org/XML/XASDM/4/SysCalTable.xsd\" schemaVersion=\"4\" schemaRevision=\"-1\">\n");
586 :
587 0 : buf.append(entity.toXML());
588 0 : string s = container.getEntity().toXML();
589 : // Change the "Entity" tag to "ContainerEntity".
590 0 : buf.append("<Container" + s.substr(1,s.length() - 1)+" ");
591 0 : vector<SysCalRow*> v = get();
592 0 : for (unsigned int i = 0; i < v.size(); ++i) {
593 : try {
594 0 : buf.append(v[i]->toXML());
595 0 : } catch (const NoSuchRow &e) {
596 0 : }
597 0 : buf.append(" ");
598 : }
599 0 : buf.append("</SysCalTable> ");
600 0 : return buf;
601 0 : }
602 :
603 :
604 0 : string SysCalTable::getVersion() const {
605 0 : return version;
606 : }
607 :
608 :
609 0 : void SysCalTable::fromXML(string& tableInXML) {
610 : //
611 : // Look for a version information in the schemaVersion of the XML
612 : //
613 : xmlDoc *doc;
614 : #if LIBXML_VERSION >= 20703
615 0 : doc = xmlReadMemory(tableInXML.data(), tableInXML.size(), "XMLTableHeader.xml", NULL, XML_PARSE_NOBLANKS|XML_PARSE_HUGE);
616 : #else
617 : doc = xmlReadMemory(tableInXML.data(), tableInXML.size(), "XMLTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
618 : #endif
619 0 : if ( doc == NULL )
620 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "SysCal");
621 :
622 0 : xmlNode* root_element = xmlDocGetRootElement(doc);
623 0 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
624 0 : throw ConversionException("Failed to retrieve the root element in the DOM structure.", "SysCal");
625 :
626 0 : xmlChar * propValue = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
627 0 : if ( propValue != 0 ) {
628 0 : version = string( (const char*) propValue);
629 0 : xmlFree(propValue);
630 : }
631 :
632 0 : Parser xml(tableInXML);
633 0 : if (!xml.isStr("<SysCalTable"))
634 0 : error();
635 : // cout << "Parsing a SysCalTable" << endl;
636 0 : string s = xml.getElement("<Entity","/>");
637 0 : if (s.length() == 0)
638 0 : error();
639 0 : Entity e;
640 0 : e.setFromXML(s);
641 0 : if (e.getEntityTypeName() != "SysCalTable")
642 0 : error();
643 0 : setEntity(e);
644 : // Skip the container's entity; but, it has to be there.
645 0 : s = xml.getElement("<ContainerEntity","/>");
646 0 : if (s.length() == 0)
647 0 : error();
648 :
649 : // Get each row in the table.
650 0 : s = xml.getElementContent("<row>","</row>");
651 : SysCalRow *row;
652 0 : if (getContainer().checkRowUniqueness()) {
653 : try {
654 0 : while (s.length() != 0) {
655 0 : row = newRow();
656 0 : row->setFromXML(s);
657 0 : checkAndAdd(row);
658 0 : s = xml.getElementContent("<row>","</row>");
659 : }
660 :
661 : }
662 0 : catch (const DuplicateKey &e1) {
663 0 : throw ConversionException(e1.getMessage(),"SysCalTable");
664 0 : }
665 0 : catch (const UniquenessViolationException &e1) {
666 0 : throw ConversionException(e1.getMessage(),"SysCalTable");
667 0 : }
668 0 : catch (...) {
669 : // cout << "Unexpected error in SysCalTable::checkAndAdd called from SysCalTable::fromXML " << endl;
670 0 : }
671 : }
672 : else {
673 : try {
674 0 : while (s.length() != 0) {
675 0 : row = newRow();
676 0 : row->setFromXML(s);
677 0 : addWithoutCheckingUnique(row);
678 0 : s = xml.getElementContent("<row>","</row>");
679 : }
680 : }
681 0 : catch (const DuplicateKey &e1) {
682 0 : throw ConversionException(e1.getMessage(),"SysCalTable");
683 0 : }
684 0 : catch (...) {
685 : // cout << "Unexpected error in SysCalTable::addWithoutCheckingUnique called from SysCalTable::fromXML " << endl;
686 0 : }
687 : }
688 :
689 :
690 0 : if (!xml.isStr("</SysCalTable>"))
691 0 : error();
692 :
693 : //Does not change the convention defined in the model.
694 : //archiveAsBin = false;
695 : //fileAsBin = false;
696 :
697 : // clean up the xmlDoc pointer
698 0 : if ( doc != NULL ) xmlFreeDoc(doc);
699 :
700 0 : }
701 :
702 :
703 0 : void SysCalTable::error() {
704 0 : throw ConversionException("Invalid xml document","SysCal");
705 : }
706 :
707 :
708 0 : string SysCalTable::MIMEXMLPart(const asdm::ByteOrder* byteOrder) {
709 0 : string UID = getEntity().getEntityId().toString();
710 0 : string withoutUID = UID.substr(6);
711 0 : string containerUID = getContainer().getEntity().getEntityId().toString();
712 0 : ostringstream oss;
713 0 : oss << "<?xml version='1.0' encoding='ISO-8859-1'?>";
714 0 : oss << "\n";
715 0 : oss << "<SysCalTable xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:syscal=\"http://Alma/XASDM/SysCalTable\" xsi:schemaLocation=\"http://Alma/XASDM/SysCalTable http://almaobservatory.org/XML/XASDM/4/SysCalTable.xsd\" schemaVersion=\"4\" schemaRevision=\"-1\">\n";
716 0 : oss<< "<Entity entityId='"<<UID<<"' entityIdEncrypted='na' entityTypeName='SysCalTable' schemaVersion='1' documentVersion='1'/>\n";
717 0 : oss<< "<ContainerEntity entityId='"<<containerUID<<"' entityIdEncrypted='na' entityTypeName='ASDM' schemaVersion='1' documentVersion='1'/>\n";
718 0 : oss << "<BulkStoreRef file_id='"<<withoutUID<<"' byteOrder='"<<byteOrder->toString()<<"' />\n";
719 0 : oss << "<Attributes>\n";
720 :
721 0 : oss << "<antennaId/>\n";
722 0 : oss << "<spectralWindowId/>\n";
723 0 : oss << "<timeInterval/>\n";
724 0 : oss << "<feedId/>\n";
725 0 : oss << "<numReceptor/>\n";
726 0 : oss << "<numChan/>\n";
727 :
728 0 : oss << "<tcalFlag/>\n";
729 0 : oss << "<tcalSpectrum/>\n";
730 0 : oss << "<trxFlag/>\n";
731 0 : oss << "<trxSpectrum/>\n";
732 0 : oss << "<tskyFlag/>\n";
733 0 : oss << "<tskySpectrum/>\n";
734 0 : oss << "<tsysFlag/>\n";
735 0 : oss << "<tsysSpectrum/>\n";
736 0 : oss << "<tantFlag/>\n";
737 0 : oss << "<tantSpectrum/>\n";
738 0 : oss << "<tantTsysFlag/>\n";
739 0 : oss << "<tantTsysSpectrum/>\n";
740 0 : oss << "<phaseDiffFlag/>\n";
741 0 : oss << "<phaseDiffSpectrum/>\n";
742 0 : oss << "</Attributes>\n";
743 0 : oss << "</SysCalTable>\n";
744 :
745 0 : return oss.str();
746 0 : }
747 :
748 0 : string SysCalTable::toMIME(const asdm::ByteOrder* byteOrder) {
749 0 : EndianOSStream eoss(byteOrder);
750 :
751 0 : string UID = getEntity().getEntityId().toString();
752 :
753 : // The MIME Header
754 0 : eoss <<"MIME-Version: 1.0";
755 0 : eoss << "\n";
756 0 : eoss << "Content-Type: Multipart/Related; boundary='MIME_boundary'; type='text/xml'; start= '<header.xml>'";
757 0 : eoss <<"\n";
758 0 : eoss <<"Content-Description: Correlator";
759 0 : eoss <<"\n";
760 0 : eoss <<"alma-uid:" << UID;
761 0 : eoss <<"\n";
762 0 : eoss <<"\n";
763 :
764 : // The MIME XML part header.
765 0 : eoss <<"--MIME_boundary";
766 0 : eoss <<"\n";
767 0 : eoss <<"Content-Type: text/xml; charset='ISO-8859-1'";
768 0 : eoss <<"\n";
769 0 : eoss <<"Content-Transfer-Encoding: 8bit";
770 0 : eoss <<"\n";
771 0 : eoss <<"Content-ID: <header.xml>";
772 0 : eoss <<"\n";
773 0 : eoss <<"\n";
774 :
775 : // The MIME XML part content.
776 0 : eoss << MIMEXMLPart(byteOrder);
777 :
778 : // The MIME binary part header
779 0 : eoss <<"--MIME_boundary";
780 0 : eoss <<"\n";
781 0 : eoss <<"Content-Type: binary/octet-stream";
782 0 : eoss <<"\n";
783 0 : eoss <<"Content-ID: <content.bin>";
784 0 : eoss <<"\n";
785 0 : eoss <<"\n";
786 :
787 : // The MIME binary content
788 0 : entity.toBin(eoss);
789 0 : container.getEntity().toBin(eoss);
790 0 : eoss.writeInt((int) privateRows.size());
791 0 : for (unsigned int i = 0; i < privateRows.size(); i++) {
792 0 : privateRows.at(i)->toBin(eoss);
793 : }
794 :
795 : // The closing MIME boundary
796 0 : eoss << "\n--MIME_boundary--";
797 0 : eoss << "\n";
798 :
799 0 : return eoss.str();
800 0 : }
801 :
802 :
803 0 : void SysCalTable::setFromMIME(const string & mimeMsg) {
804 0 : string xmlPartMIMEHeader = "Content-ID: <header.xml>\n\n";
805 :
806 0 : string binPartMIMEHeader = "--MIME_boundary\nContent-Type: binary/octet-stream\nContent-ID: <content.bin>\n\n";
807 :
808 : // Detect the XML header.
809 0 : string::size_type loc0 = mimeMsg.find(xmlPartMIMEHeader, 0);
810 0 : if ( loc0 == string::npos) {
811 : // let's try with CRLFs
812 0 : xmlPartMIMEHeader = "Content-ID: <header.xml>\r\n\r\n";
813 0 : loc0 = mimeMsg.find(xmlPartMIMEHeader, 0);
814 0 : if ( loc0 == string::npos )
815 0 : throw ConversionException("Failed to detect the beginning of the XML header", "SysCal");
816 : }
817 :
818 0 : loc0 += xmlPartMIMEHeader.size();
819 :
820 : // Look for the string announcing the binary part.
821 0 : string::size_type loc1 = mimeMsg.find( binPartMIMEHeader, loc0 );
822 :
823 0 : if ( loc1 == string::npos ) {
824 0 : throw ConversionException("Failed to detect the beginning of the binary part", "SysCal");
825 : }
826 :
827 : //
828 : // Extract the xmlHeader and analyze it to find out what is the byte order and the sequence
829 : // of attribute names.
830 : //
831 0 : string xmlHeader = mimeMsg.substr(loc0, loc1-loc0);
832 : xmlDoc *doc;
833 0 : doc = xmlReadMemory(xmlHeader.data(), xmlHeader.size(), "BinaryTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
834 0 : if ( doc == NULL )
835 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "SysCal");
836 :
837 : // This vector will be filled by the names of all the attributes of the table
838 : // in the order in which they are expected to be found in the binary representation.
839 : //
840 0 : vector<string> attributesSeq;
841 :
842 0 : xmlNode* root_element = xmlDocGetRootElement(doc);
843 0 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
844 0 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "SysCal");
845 :
846 0 : const ByteOrder* byteOrder=0;
847 0 : if ( string("ASDMBinaryTable").compare((const char*) root_element->name) == 0) {
848 : // Then it's an "old fashioned" MIME file for tables.
849 : // Just try to deserialize it with Big_Endian for the bytes ordering.
850 0 : byteOrder = asdm::ByteOrder::Big_Endian;
851 :
852 : //
853 : // Let's consider a default order for the sequence of attributes.
854 : //
855 :
856 :
857 0 : attributesSeq.push_back("antennaId") ;
858 :
859 0 : attributesSeq.push_back("spectralWindowId") ;
860 :
861 0 : attributesSeq.push_back("timeInterval") ;
862 :
863 0 : attributesSeq.push_back("feedId") ;
864 :
865 0 : attributesSeq.push_back("numReceptor") ;
866 :
867 0 : attributesSeq.push_back("numChan") ;
868 :
869 :
870 0 : attributesSeq.push_back("tcalFlag") ;
871 :
872 0 : attributesSeq.push_back("tcalSpectrum") ;
873 :
874 0 : attributesSeq.push_back("trxFlag") ;
875 :
876 0 : attributesSeq.push_back("trxSpectrum") ;
877 :
878 0 : attributesSeq.push_back("tskyFlag") ;
879 :
880 0 : attributesSeq.push_back("tskySpectrum") ;
881 :
882 0 : attributesSeq.push_back("tsysFlag") ;
883 :
884 0 : attributesSeq.push_back("tsysSpectrum") ;
885 :
886 0 : attributesSeq.push_back("tantFlag") ;
887 :
888 0 : attributesSeq.push_back("tantSpectrum") ;
889 :
890 0 : attributesSeq.push_back("tantTsysFlag") ;
891 :
892 0 : attributesSeq.push_back("tantTsysSpectrum") ;
893 :
894 0 : attributesSeq.push_back("phaseDiffFlag") ;
895 :
896 0 : attributesSeq.push_back("phaseDiffSpectrum") ;
897 :
898 :
899 :
900 :
901 : // And decide that it has version == "2"
902 0 : version = "2";
903 : }
904 0 : else if (string("SysCalTable").compare((const char*) root_element->name) == 0) {
905 : // It's a new (and correct) MIME file for tables.
906 : //
907 : // 1st ) Look for a BulkStoreRef element with an attribute byteOrder.
908 : //
909 0 : xmlNode* bulkStoreRef = 0;
910 0 : xmlNode* child = root_element->children;
911 :
912 0 : if (xmlHasProp(root_element, (const xmlChar*) "schemaVersion")) {
913 0 : xmlChar * value = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
914 0 : version = string ((const char *) value);
915 0 : xmlFree(value);
916 : }
917 :
918 : // Skip the two first children (Entity and ContainerEntity).
919 0 : bulkStoreRef = (child == 0) ? 0 : ( (child->next) == 0 ? 0 : child->next->next );
920 :
921 0 : if ( bulkStoreRef == 0 || (bulkStoreRef->type != XML_ELEMENT_NODE) || (string("BulkStoreRef").compare((const char*) bulkStoreRef->name) != 0))
922 0 : throw ConversionException ("Could not find the element '/SysCalTable/BulkStoreRef'. Invalid XML header '"+ xmlHeader + "'.", "SysCal");
923 :
924 : // We found BulkStoreRef, now look for its attribute byteOrder.
925 0 : _xmlAttr* byteOrderAttr = 0;
926 0 : for (struct _xmlAttr* attr = bulkStoreRef->properties; attr; attr = attr->next)
927 0 : if (string("byteOrder").compare((const char*) attr->name) == 0) {
928 0 : byteOrderAttr = attr;
929 0 : break;
930 : }
931 :
932 0 : if (byteOrderAttr == 0)
933 0 : throw ConversionException("Could not find the element '/SysCalTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader +"'.", "SysCal");
934 :
935 0 : string byteOrderValue = string((const char*) byteOrderAttr->children->content);
936 0 : if (!(byteOrder = asdm::ByteOrder::fromString(byteOrderValue)))
937 0 : throw ConversionException("No valid value retrieved for the element '/SysCalTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader + "'.", "SysCal");
938 :
939 : //
940 : // 2nd) Look for the Attributes element and grab the names of the elements it contains.
941 : //
942 0 : xmlNode* attributes = bulkStoreRef->next;
943 0 : if ( attributes == 0 || (attributes->type != XML_ELEMENT_NODE) || (string("Attributes").compare((const char*) attributes->name) != 0))
944 0 : throw ConversionException ("Could not find the element '/SysCalTable/Attributes'. Invalid XML header '"+ xmlHeader + "'.", "SysCal");
945 :
946 0 : xmlNode* childOfAttributes = attributes->children;
947 :
948 0 : while ( childOfAttributes != 0 && (childOfAttributes->type == XML_ELEMENT_NODE) ) {
949 0 : attributesSeq.push_back(string((const char*) childOfAttributes->name));
950 0 : childOfAttributes = childOfAttributes->next;
951 : }
952 0 : }
953 : // Create an EndianISStream from the substring containing the binary part.
954 0 : EndianISStream eiss(mimeMsg.substr(loc1+binPartMIMEHeader.size()), byteOrder);
955 :
956 0 : entity = Entity::fromBin((EndianIStream&) eiss);
957 :
958 : // We do nothing with that but we have to read it.
959 0 : Entity containerEntity = Entity::fromBin((EndianIStream&) eiss);
960 :
961 : // Let's read numRows but ignore it and rely on the value specified in the ASDM.xml file.
962 0 : int numRows = ((EndianIStream&) eiss).readInt();
963 0 : if ((numRows != -1) // Then these are *not* data produced at the EVLA.
964 0 : && ((unsigned int) numRows != this->declaredSize )) { // Then the declared size (in ASDM.xml) is not equal to the one
965 : // written into the binary representation of the table.
966 0 : cout << "The a number of rows ('"
967 : << numRows
968 0 : << "') declared in the binary representation of the table is different from the one declared in ASDM.xml ('"
969 0 : << this->declaredSize
970 0 : << "'). I'll proceed with the value declared in ASDM.xml"
971 0 : << endl;
972 : }
973 :
974 0 : if (getContainer().checkRowUniqueness()) {
975 : try {
976 0 : for (uint32_t i = 0; i < this->declaredSize; i++) {
977 0 : SysCalRow* aRow = SysCalRow::fromBin((EndianIStream&) eiss, *this, attributesSeq);
978 0 : checkAndAdd(aRow);
979 : }
980 : }
981 0 : catch (const DuplicateKey &e) {
982 0 : throw ConversionException("Error while writing binary data , the message was "
983 0 : + e.getMessage(), "SysCal");
984 0 : }
985 0 : catch (const TagFormatException &e) {
986 0 : throw ConversionException("Error while reading binary data , the message was "
987 0 : + e.getMessage(), "SysCal");
988 0 : }
989 : }
990 : else {
991 0 : for (uint32_t i = 0; i < this->declaredSize; i++) {
992 0 : SysCalRow* aRow = SysCalRow::fromBin((EndianIStream&) eiss, *this, attributesSeq);
993 0 : append(aRow);
994 : }
995 : }
996 : //Does not change the convention defined in the model.
997 : //archiveAsBin = true;
998 : //fileAsBin = true;
999 0 : if ( doc != NULL ) xmlFreeDoc(doc);
1000 :
1001 0 : }
1002 :
1003 0 : void SysCalTable::setUnknownAttributeBinaryReader(const string& attributeName, BinaryAttributeReaderFunctor* barFctr) {
1004 : //
1005 : // Is this attribute really unknown ?
1006 : //
1007 0 : for (vector<string>::const_iterator iter = attributesNamesOfSysCal_v.begin(); iter != attributesNamesOfSysCal_v.end(); iter++) {
1008 0 : if ((*iter).compare(attributeName) == 0)
1009 0 : throw ConversionException("the attribute '"+attributeName+"' is known you can't override the way it's read in the MIME binary file containing the table.", "SysCal");
1010 : }
1011 :
1012 : // Ok then register the functor to activate when an unknown attribute is met during the reading of a binary table?
1013 0 : unknownAttributes2Functors[attributeName] = barFctr;
1014 0 : }
1015 :
1016 0 : BinaryAttributeReaderFunctor* SysCalTable::getUnknownAttributeBinaryReader(const string& attributeName) const {
1017 0 : map<string, BinaryAttributeReaderFunctor*>::const_iterator iter = unknownAttributes2Functors.find(attributeName);
1018 0 : return (iter == unknownAttributes2Functors.end()) ? 0 : iter->second;
1019 : }
1020 :
1021 :
1022 0 : void SysCalTable::toFile(string directory) {
1023 0 : if (!directoryExists(directory.c_str()) &&
1024 0 : !createPath(directory.c_str())) {
1025 0 : throw ConversionException("Could not create directory " , directory);
1026 : }
1027 :
1028 0 : string fileName = directory + "/SysCal.xml";
1029 0 : ofstream tableout(fileName.c_str(),ios::out|ios::trunc);
1030 0 : if (tableout.rdstate() == ostream::failbit)
1031 0 : throw ConversionException("Could not open file " + fileName + " to write ", "SysCal");
1032 0 : if (fileAsBin)
1033 0 : tableout << MIMEXMLPart();
1034 : else
1035 0 : tableout << toXML() << endl;
1036 0 : tableout.close();
1037 0 : if (tableout.rdstate() == ostream::failbit)
1038 0 : throw ConversionException("Could not close file " + fileName, "SysCal");
1039 :
1040 0 : if (fileAsBin) {
1041 : // write the bin serialized
1042 0 : string fileName = directory + "/SysCal.bin";
1043 0 : ofstream tableout(fileName.c_str(),ios::out|ios::trunc);
1044 0 : if (tableout.rdstate() == ostream::failbit)
1045 0 : throw ConversionException("Could not open file " + fileName + " to write ", "SysCal");
1046 0 : tableout << toMIME() << endl;
1047 0 : tableout.close();
1048 0 : if (tableout.rdstate() == ostream::failbit)
1049 0 : throw ConversionException("Could not close file " + fileName, "SysCal");
1050 0 : }
1051 0 : }
1052 :
1053 :
1054 0 : void SysCalTable::setFromFile(const string& directory) {
1055 : #ifndef WITHOUT_BOOST
1056 : if (boost::filesystem::exists(boost::filesystem::path(uniqSlashes(directory + "/SysCal.xml"))))
1057 : setFromXMLFile(directory);
1058 : else if (boost::filesystem::exists(boost::filesystem::path(uniqSlashes(directory + "/SysCal.bin"))))
1059 : setFromMIMEFile(directory);
1060 : #else
1061 : // alternative in Misc.h
1062 0 : if (file_exists(uniqSlashes(directory + "/SysCal.xml")))
1063 0 : setFromXMLFile(directory);
1064 0 : else if (file_exists(uniqSlashes(directory + "/SysCal.bin")))
1065 0 : setFromMIMEFile(directory);
1066 : #endif
1067 : else
1068 0 : throw ConversionException("No file found for the SysCal table", "SysCal");
1069 0 : }
1070 :
1071 :
1072 0 : void SysCalTable::setFromMIMEFile(const string& directory) {
1073 0 : string tablePath ;
1074 :
1075 0 : tablePath = directory + "/SysCal.bin";
1076 0 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1077 0 : if (!tablefile.is_open()) {
1078 0 : throw ConversionException("Could not open file " + tablePath, "SysCal");
1079 : }
1080 : // Read in a stringstream.
1081 0 : stringstream ss; ss << tablefile.rdbuf();
1082 :
1083 0 : if (tablefile.rdstate() == istream::failbit || tablefile.rdstate() == istream::badbit) {
1084 0 : throw ConversionException("Error reading file " + tablePath,"SysCal");
1085 : }
1086 :
1087 : // And close.
1088 0 : tablefile.close();
1089 0 : if (tablefile.rdstate() == istream::failbit)
1090 0 : throw ConversionException("Could not close file " + tablePath,"SysCal");
1091 :
1092 0 : setFromMIME(ss.str());
1093 0 : }
1094 : /*
1095 : void SysCalTable::openMIMEFile (const string& directory) {
1096 :
1097 : // Open the file.
1098 : string tablePath ;
1099 : tablePath = directory + "/SysCal.bin";
1100 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1101 : if (!tablefile.is_open())
1102 : throw ConversionException("Could not open file " + tablePath, "SysCal");
1103 :
1104 : // Locate the xmlPartMIMEHeader.
1105 : string xmlPartMIMEHeader = "CONTENT-ID: <HEADER.XML>\n\n";
1106 : CharComparator comparator;
1107 : istreambuf_iterator<char> BEGIN(tablefile.rdbuf());
1108 : istreambuf_iterator<char> END;
1109 : istreambuf_iterator<char> it = search(BEGIN, END, xmlPartMIMEHeader.begin(), xmlPartMIMEHeader.end(), comparator);
1110 : if (it == END)
1111 : throw ConversionException("failed to detect the beginning of the XML header", "SysCal");
1112 :
1113 : // Locate the binaryPartMIMEHeader while accumulating the characters of the xml header.
1114 : string binPartMIMEHeader = "--MIME_BOUNDARY\nCONTENT-TYPE: BINARY/OCTET-STREAM\nCONTENT-ID: <CONTENT.BIN>\n\n";
1115 : string xmlHeader;
1116 : CharCompAccumulator compaccumulator(&xmlHeader, 100000);
1117 : ++it;
1118 : it = search(it, END, binPartMIMEHeader.begin(), binPartMIMEHeader.end(), compaccumulator);
1119 : if (it == END)
1120 : throw ConversionException("failed to detect the beginning of the binary part", "SysCal");
1121 :
1122 : cout << xmlHeader << endl;
1123 : //
1124 : // We have the xmlHeader , let's parse it.
1125 : //
1126 : xmlDoc *doc;
1127 : doc = xmlReadMemory(xmlHeader.data(), xmlHeader.size(), "BinaryTableHeader.xml", NULL, XML_PARSE_NOBLANKS);
1128 : if ( doc == NULL )
1129 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "SysCal");
1130 :
1131 : // This vector will be filled by the names of all the attributes of the table
1132 : // in the order in which they are expected to be found in the binary representation.
1133 : //
1134 : vector<string> attributesSeq(attributesNamesInBinOfSysCal_v);
1135 :
1136 : xmlNode* root_element = xmlDocGetRootElement(doc);
1137 : if ( root_element == NULL || root_element->type != XML_ELEMENT_NODE )
1138 : throw ConversionException("Failed to parse the xmlHeader into a DOM structure.", "SysCal");
1139 :
1140 : const ByteOrder* byteOrder=0;
1141 : if ( string("ASDMBinaryTable").compare((const char*) root_element->name) == 0) {
1142 : // Then it's an "old fashioned" MIME file for tables.
1143 : // Just try to deserialize it with Big_Endian for the bytes ordering.
1144 : byteOrder = asdm::ByteOrder::Big_Endian;
1145 :
1146 : // And decide that it has version == "2"
1147 : version = "2";
1148 : }
1149 : else if (string("SysCalTable").compare((const char*) root_element->name) == 0) {
1150 : // It's a new (and correct) MIME file for tables.
1151 : //
1152 : // 1st ) Look for a BulkStoreRef element with an attribute byteOrder.
1153 : //
1154 : xmlNode* bulkStoreRef = 0;
1155 : xmlNode* child = root_element->children;
1156 :
1157 : if (xmlHasProp(root_element, (const xmlChar*) "schemaVersion")) {
1158 : xmlChar * value = xmlGetProp(root_element, (const xmlChar *) "schemaVersion");
1159 : version = string ((const char *) value);
1160 : xmlFree(value);
1161 : }
1162 :
1163 : // Skip the two first children (Entity and ContainerEntity).
1164 : bulkStoreRef = (child == 0) ? 0 : ( (child->next) == 0 ? 0 : child->next->next );
1165 :
1166 : if ( bulkStoreRef == 0 || (bulkStoreRef->type != XML_ELEMENT_NODE) || (string("BulkStoreRef").compare((const char*) bulkStoreRef->name) != 0))
1167 : throw ConversionException ("Could not find the element '/SysCalTable/BulkStoreRef'. Invalid XML header '"+ xmlHeader + "'.", "SysCal");
1168 :
1169 : // We found BulkStoreRef, now look for its attribute byteOrder.
1170 : _xmlAttr* byteOrderAttr = 0;
1171 : for (struct _xmlAttr* attr = bulkStoreRef->properties; attr; attr = attr->next)
1172 : if (string("byteOrder").compare((const char*) attr->name) == 0) {
1173 : byteOrderAttr = attr;
1174 : break;
1175 : }
1176 :
1177 : if (byteOrderAttr == 0)
1178 : throw ConversionException("Could not find the element '/SysCalTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader +"'.", "SysCal");
1179 :
1180 : string byteOrderValue = string((const char*) byteOrderAttr->children->content);
1181 : if (!(byteOrder = asdm::ByteOrder::fromString(byteOrderValue)))
1182 : throw ConversionException("No valid value retrieved for the element '/SysCalTable/BulkStoreRef/@byteOrder'. Invalid XML header '" + xmlHeader + "'.", "SysCal");
1183 :
1184 : //
1185 : // 2nd) Look for the Attributes element and grab the names of the elements it contains.
1186 : //
1187 : xmlNode* attributes = bulkStoreRef->next;
1188 : if ( attributes == 0 || (attributes->type != XML_ELEMENT_NODE) || (string("Attributes").compare((const char*) attributes->name) != 0))
1189 : throw ConversionException ("Could not find the element '/SysCalTable/Attributes'. Invalid XML header '"+ xmlHeader + "'.", "SysCal");
1190 :
1191 : xmlNode* childOfAttributes = attributes->children;
1192 :
1193 : while ( childOfAttributes != 0 && (childOfAttributes->type == XML_ELEMENT_NODE) ) {
1194 : attributesSeq.push_back(string((const char*) childOfAttributes->name));
1195 : childOfAttributes = childOfAttributes->next;
1196 : }
1197 : }
1198 : // Create an EndianISStream from the substring containing the binary part.
1199 : EndianIFStream eifs(&tablefile, byteOrder);
1200 :
1201 : entity = Entity::fromBin((EndianIStream &) eifs);
1202 :
1203 : // We do nothing with that but we have to read it.
1204 : Entity containerEntity = Entity::fromBin((EndianIStream &) eifs);
1205 :
1206 : // Let's read numRows but ignore it and rely on the value specified in the ASDM.xml file.
1207 : int numRows = eifs.readInt();
1208 : if ((numRows != -1) // Then these are *not* data produced at the EVLA.
1209 : && ((unsigned int) numRows != this->declaredSize )) { // Then the declared size (in ASDM.xml) is not equal to the one
1210 : // written into the binary representation of the table.
1211 : cout << "The a number of rows ('"
1212 : << numRows
1213 : << "') declared in the binary representation of the table is different from the one declared in ASDM.xml ('"
1214 : << this->declaredSize
1215 : << "'). I'll proceed with the value declared in ASDM.xml"
1216 : << endl;
1217 : }
1218 : // clean up xmlDoc pointer
1219 : if ( doc != NULL ) xmlFreeDoc(doc);
1220 : }
1221 : */
1222 :
1223 :
1224 0 : void SysCalTable::setFromXMLFile(const string& directory) {
1225 0 : string tablePath ;
1226 :
1227 0 : tablePath = directory + "/SysCal.xml";
1228 :
1229 : /*
1230 : ifstream tablefile(tablePath.c_str(), ios::in|ios::binary);
1231 : if (!tablefile.is_open()) {
1232 : throw ConversionException("Could not open file " + tablePath, "SysCal");
1233 : }
1234 : // Read in a stringstream.
1235 : stringstream ss;
1236 : ss << tablefile.rdbuf();
1237 :
1238 : if (tablefile.rdstate() == istream::failbit || tablefile.rdstate() == istream::badbit) {
1239 : throw ConversionException("Error reading file '" + tablePath + "'", "SysCal");
1240 : }
1241 :
1242 : // And close
1243 : tablefile.close();
1244 : if (tablefile.rdstate() == istream::failbit)
1245 : throw ConversionException("Could not close file '" + tablePath + "'", "SysCal");
1246 :
1247 : // Let's make a string out of the stringstream content and empty the stringstream.
1248 : string xmlDocument = ss.str(); ss.str("");
1249 :
1250 : // Let's make a very primitive check to decide
1251 : // whether the XML content represents the table
1252 : // or refers to it via a <BulkStoreRef element.
1253 : */
1254 :
1255 0 : string xmlDocument;
1256 : try {
1257 0 : xmlDocument = getContainer().getXSLTransformer()(tablePath);
1258 0 : if (getenv("ASDM_DEBUG")) cout << "About to read " << tablePath << endl;
1259 : }
1260 0 : catch (const XSLTransformerException &e) {
1261 0 : throw ConversionException("Caugth an exception whose message is '" + e.getMessage() + "'.", "SysCal");
1262 0 : }
1263 :
1264 0 : if (xmlDocument.find("<BulkStoreRef") != string::npos)
1265 0 : setFromMIMEFile(directory);
1266 : else
1267 0 : fromXML(xmlDocument);
1268 0 : }
1269 :
1270 :
1271 :
1272 :
1273 :
1274 :
1275 :
1276 :
1277 :
1278 : /**
1279 : * Insert a SysCalRow* in a vector of SysCalRow* so that it's ordered by ascending start time.
1280 : *
1281 : * @param SysCalRow* x . The pointer to be inserted.
1282 : * @param vector <SysCalRow*>& row. A reference to the vector where to insert x.
1283 : *
1284 : */
1285 0 : SysCalRow* SysCalTable::insertByStartTime(SysCalRow* x, vector<SysCalRow*>& row) {
1286 :
1287 0 : vector <SysCalRow*>::iterator theIterator;
1288 :
1289 0 : ArrayTime start = x->timeInterval.getStart();
1290 :
1291 : // Is the row vector empty ?
1292 0 : if (row.size() == 0) {
1293 0 : row.push_back(x);
1294 0 : privateRows.push_back(x);
1295 0 : x->isAdded(true);
1296 0 : return x;
1297 : }
1298 :
1299 : // Optimization for the case of insertion by ascending time.
1300 0 : SysCalRow* last = *(row.end()-1);
1301 :
1302 0 : if ( start > last->timeInterval.getStart() ) {
1303 : //
1304 : // Modify the duration of last if and only if the start time of x
1305 : // is located strictly before the end time of last.
1306 : //
1307 0 : if ( start < (last->timeInterval.getStart() + last->timeInterval.getDuration()))
1308 0 : last->timeInterval.setDuration(start - last->timeInterval.getStart());
1309 0 : row.push_back(x);
1310 0 : privateRows.push_back(x);
1311 0 : x->isAdded(true);
1312 0 : return x;
1313 : }
1314 :
1315 : // Optimization for the case of insertion by descending time.
1316 0 : SysCalRow* first = *(row.begin());
1317 :
1318 0 : if ( start < first->timeInterval.getStart() ) {
1319 : //
1320 : // Modify the duration of x if and only if the start time of first
1321 : // is located strictly before the end time of x.
1322 : //
1323 0 : if ( first->timeInterval.getStart() < (start + x->timeInterval.getDuration()) )
1324 0 : x->timeInterval.setDuration(first->timeInterval.getStart() - start);
1325 0 : row.insert(row.begin(), x);
1326 0 : privateRows.push_back(x);
1327 0 : x->isAdded(true);
1328 0 : return x;
1329 : }
1330 :
1331 : // Case where x has to be inserted inside row; let's use a dichotomy
1332 : // method to find the insertion index.
1333 0 : unsigned int k0 = 0;
1334 0 : unsigned int k1 = row.size() - 1;
1335 :
1336 0 : while (k0 != (k1 - 1)) {
1337 0 : if (start == row[k0]->timeInterval.getStart()) {
1338 0 : if (row[k0]->equalByRequiredValue(x))
1339 0 : return row[k0];
1340 : else
1341 0 : throw DuplicateKey("DuplicateKey exception in ", "SysCalTable");
1342 : }
1343 0 : else if (start == row[k1]->timeInterval.getStart()) {
1344 0 : if (row[k1]->equalByRequiredValue(x))
1345 0 : return row[k1];
1346 : else
1347 0 : throw DuplicateKey("DuplicateKey exception in ", "SysCalTable");
1348 : }
1349 : else {
1350 0 : if (start <= row[(k0+k1)/2]->timeInterval.getStart())
1351 0 : k1 = (k0 + k1) / 2;
1352 : else
1353 0 : k0 = (k0 + k1) / 2;
1354 : }
1355 : }
1356 :
1357 0 : if (start == row[k0]->timeInterval.getStart()) {
1358 0 : if (row[k0]->equalByRequiredValue(x))
1359 0 : return row[k0];
1360 : else
1361 0 : throw DuplicateKey("DuplicateKey exception in ", "SysCalTable");
1362 : }
1363 0 : else if (start == row[k1]->timeInterval.getStart()) {
1364 0 : if (row[k1]->equalByRequiredValue(x))
1365 0 : return row[k1];
1366 : else
1367 0 : throw DuplicateKey("DuplicateKey exception in ", "SysCalTable");
1368 : }
1369 :
1370 0 : row[k0]->timeInterval.setDuration(start-row[k0]->timeInterval.getStart());
1371 0 : x->timeInterval.setDuration(row[k0+1]->timeInterval.getStart() - start);
1372 0 : row.insert(row.begin()+(k0+1), x);
1373 0 : privateRows.push_back(x);
1374 0 : x->isAdded(true);
1375 0 : return x;
1376 0 : }
1377 :
1378 :
1379 :
1380 :
1381 :
1382 : } // End namespace asdm
1383 :
|