3e1662ae1b91ab65ed81f73635efe05c9fe82035
[ctsim.git] / libctsim / array2dfile.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **      Name:         array2dfile.cpp
5 **      Purpose:      2-dimension array file class
6 **      Programmer:   Kevin Rosenberg
7 **      Date Started: June 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (c) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id$
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #include "array2dfile.h"
29 #include <ctime>
30 #ifdef MSVC
31 typedef long off_t;
32 #endif
33
34 #include <sstream>
35
36 const kuint16 Array2dFile::m_signature = ('I'*256+'F');
37
38 ///////////////////////////////////////////////////////////////////////////
39 // CLASS IMPLEMENTATION
40 //
41 //     Name: Array2dFileLabel
42 //     Purpose: Labels for Array2dFiles
43 ///////////////////////////////////////////////////////////////////////////
44
45 void
46 Array2dFileLabel::init (void)
47 {
48   m_calcTime = 0;
49   m_labelType = L_EMPTY;
50   time_t t = time(0);
51   tm* lt = localtime(&t);
52   m_year = lt->tm_year;
53   m_month = lt->tm_mon;
54   m_day = lt->tm_mday;
55   m_hour = lt->tm_hour;
56   m_minute = lt->tm_min;
57   m_second = lt->tm_sec;
58 }
59
60 Array2dFileLabel::Array2dFileLabel() 
61 {
62   init();
63 }
64
65 Array2dFileLabel::Array2dFileLabel(const char* const str, double ctime)
66 : m_strLabel (str)
67 {
68   init();
69   
70   m_labelType = L_USER;
71   m_calcTime = ctime;
72 }
73
74 Array2dFileLabel::Array2dFileLabel(const int type, const char* const str, double ctime)
75 :  m_strLabel (str)
76 {
77   init();
78   
79   m_labelType = type;
80   m_calcTime = ctime;
81 }
82
83 Array2dFileLabel::~Array2dFileLabel()
84 {
85 }
86
87 void 
88 Array2dFileLabel::setDateTime (int year, int month, int day, int hour, int minute, int second)
89 {
90   m_year = year;
91   m_month = month;
92   m_day = day;
93   m_hour = hour;
94   m_minute = minute;
95   m_second = second;
96 }
97
98 void 
99 Array2dFileLabel::getDateTime (int& year, int& month, int& day, int& hour, int& minute, int& second) const
100 {
101   year = m_year;
102   month = m_month;
103   day = m_day;
104   hour = m_hour;
105   minute = m_minute;
106   second = m_second;
107 }
108
109 const std::string& 
110 Array2dFileLabel::getDateString (void) const
111 {
112   char szDate [128];
113   snprintf (szDate, sizeof(szDate), "%2d/%02d/%4d %02d:%02d:%02d",
114     m_month + 1, m_day, m_year + 1900, m_hour, m_minute, m_second);
115   m_strDate = szDate;
116   return m_strDate;
117 }
118
119
120 Array2dFileLabel::Array2dFileLabel (const Array2dFileLabel& rhs)
121 {
122   m_calcTime = rhs.m_calcTime;
123   m_labelType = rhs.m_labelType;
124   m_strLabel = rhs.m_strLabel;
125   m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
126   m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
127 }
128
129 Array2dFileLabel&
130 Array2dFileLabel::operator= (const Array2dFileLabel& rhs)
131 {
132   m_calcTime = rhs.m_calcTime;
133   m_labelType = rhs.m_labelType;
134   m_strLabel = rhs.m_strLabel;
135   m_year = rhs.m_year; m_month = rhs.m_month; m_day = rhs.m_day;
136   m_hour = rhs.m_hour; m_minute = rhs.m_minute; m_second = rhs.m_second;
137   
138   return (*this);
139 }
140
141 void
142 Array2dFileLabel::print (std::ostream& os) const
143 {
144   if (m_labelType == L_HISTORY) {
145     os << "History: " << std::endl;
146     os << "  " << m_strLabel << std::endl;
147     os << "  calc time = " << m_calcTime << " secs" << std::endl;
148     os << "  Timestamp = " << getDateString() << std::endl;
149   } else if (m_labelType == L_USER) {
150     os << "Note: " <<  m_strLabel << std::endl;
151     os << "  Timestamp = %s" << getDateString() << std::endl;
152   } else {
153     os << "Unknown (" << m_labelType << "): " <<  m_strLabel << std::endl;
154     os << "  Timestamp = %s" << getDateString() << std::endl;
155   }
156 }
157
158 void
159 Array2dFileLabel::printBrief (std::ostream& os) const
160 {
161   if (m_labelType == L_HISTORY) {
162     os << "History (";
163     if (m_calcTime > 0)
164       os << m_calcTime << " secs, ";
165     os << getDateString() << "): " << m_strLabel << std::endl;
166   } else if (m_labelType == L_USER) {
167     os << "Note (" <<  getDateString() << "): " << m_strLabel << std::endl;
168   } else {
169     os << "Unknown (" << getDateString() << "): " << m_strLabel << std::endl;
170   }
171 }
172
173 void
174 Array2dFileLabel::printBrief (std::ostringstream& os) const
175 {
176   if (m_labelType == L_HISTORY) {
177     os << "History (";
178     if (m_calcTime > 0)
179       os << m_calcTime << " secs, ";
180     os << getDateString().c_str() << "): " << m_strLabel.c_str() << "\n";
181   } else if (m_labelType == L_USER) {
182     os << "Note (" <<  getDateString() << "): " << m_strLabel << "\n";
183   } else {
184     os << "Unknown (" << getDateString() << "): " << m_strLabel << "\n";
185   }
186 }
187
188
189 ///////////////////////////////////////////////////////////////////////////
190 // CLASS IMPLEMENTATION
191 //
192 //     Name: Array2dFile
193 //     Purpose: Array2dFiles
194 ///////////////////////////////////////////////////////////////////////////
195
196
197 Array2dFile::Array2dFile (int x, int y, int pixelSize, int pixelFormat, int dataType)
198 {
199   init();
200   setArraySize (x, y, pixelSize, pixelFormat, dataType);
201 }
202
203 Array2dFile::~Array2dFile (void)
204 {
205   freeArrays ();
206   for (labelIterator l = m_labels.begin(); l != m_labels.end(); l++)
207     delete *l;
208 }
209
210 Array2dFile::Array2dFile (void)
211 {
212   init();
213 }
214
215 void
216 Array2dFile::init (void)
217 {
218   m_pixelSize = 0;
219   m_pixelFormat = PIXEL_INVALID;
220   m_arrayData = NULL;
221   m_imaginaryArrayData = NULL;
222   m_dataType = DATA_TYPE_INVALID;
223   m_nx = 0;
224   m_ny = 0;
225   m_headersize = 0;
226   m_axisIncrementKnown = false;
227   m_axisIncrementX = m_axisIncrementY = 0;
228   m_axisExtentKnown = false;
229   m_minX = m_maxX = m_minY = m_maxY = 0;
230   m_offsetPV = 0;
231   m_scalePV = 1;
232 }
233
234
235 void
236 Array2dFile::setArraySize (int x, int y, int pixelSize, int pixelFormat, int dataType)
237 {
238   m_pixelSize = pixelSize;
239   m_pixelFormat = pixelFormat;
240   m_dataType = dataType;
241   setArraySize (x, y);
242 }
243
244 void
245 Array2dFile::setArraySize (int x, int y)
246 {
247   m_nx = x;
248   m_ny = y;
249   allocArrays ();
250 }
251
252 bool
253 Array2dFile::reallocComplexToReal ()
254 {
255   if (m_dataType != DATA_TYPE_COMPLEX)
256     return false;
257
258   freeArray (m_imaginaryArrayData);
259   m_dataType = DATA_TYPE_REAL;
260
261   return true;
262 }
263
264
265 bool
266 Array2dFile::reallocRealToComplex ()
267 {
268   if (m_dataType != DATA_TYPE_REAL)
269     return false;
270
271   allocArray (m_imaginaryArrayData);
272   m_dataType = DATA_TYPE_COMPLEX;
273
274   return true;
275 }
276
277
278
279 void 
280 Array2dFile::allocArrays ()
281 {
282   if (m_arrayData) 
283     freeArray (m_arrayData);
284   if (m_imaginaryArrayData)
285     freeArray (m_imaginaryArrayData);
286
287   allocArray (m_arrayData);
288   if (m_dataType == DATA_TYPE_COMPLEX)
289     allocArray (m_imaginaryArrayData);
290 }
291
292 void
293 Array2dFile::allocArray (unsigned char**& rppData)
294 {
295   m_arraySize = m_nx * m_ny * m_pixelSize;
296   rppData = new unsigned char* [m_nx];
297   int columnBytes = m_ny * m_pixelSize;
298   for (unsigned int i = 0; i < m_nx; i++)
299     rppData[i] = new unsigned char [columnBytes];
300 }
301
302 void 
303 Array2dFile::freeArrays ()
304 {
305   if (m_arrayData) 
306     freeArray (m_arrayData);
307   
308   if (m_imaginaryArrayData) 
309     freeArray (m_imaginaryArrayData);
310   
311 }
312
313 void
314 Array2dFile::freeArray (unsigned char**& rppData)
315 {
316    for (unsigned int i = 0; i < m_nx; i++)
317       delete rppData[i];
318     delete rppData;
319     rppData = NULL;
320 }
321
322
323 bool
324 Array2dFile::fileWrite (const std::string& filename)
325 {
326   return fileWrite (filename.c_str());
327 }
328
329 bool
330 Array2dFile::fileWrite (const char* const filename)
331 {
332   m_filename = filename;
333   
334   frnetorderstream fs (m_filename.c_str(), std::ios::out | std::ios::in | std::ios::trunc | std::ios::binary);
335   if (fs.fail()) {
336     sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", m_filename.c_str());
337     return false;
338   }
339   if (! headerWrite(fs))
340     return false;
341   
342   if (! arrayDataWrite (fs))
343     return false;
344   
345   if (! labelsWrite (fs))
346     return false;
347   
348   return true;
349 }
350
351 bool
352 Array2dFile::fileRead (const std::string& filename)
353 {
354   return fileRead (filename.c_str());
355 }
356
357 bool
358 Array2dFile::fileRead (const char* const filename)
359 {
360   m_filename = filename;
361   
362   frnetorderstream fs (m_filename.c_str(), std::ios::out | std::ios::in | std::ios::binary);
363
364   if (fs.fail()) {
365     sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", m_filename.c_str());
366     return false;
367   }
368   
369   if (! headerRead(fs))
370     return false;
371   
372   allocArrays ();
373   
374   if (! arrayDataRead(fs))
375     return false;;
376   
377   if (! labelsRead (fs))
378     return false;
379   
380   return true;
381 }
382
383 void
384 Array2dFile::setAxisIncrement (double incX, double incY)
385 {
386   m_axisIncrementKnown = true;
387   m_axisIncrementX = incX;
388   m_axisIncrementY = incY;
389 }
390
391 void 
392 Array2dFile::setAxisExtent (double minX, double maxX, double minY, double maxY)
393 {
394   m_axisExtentKnown = true;
395   m_minX = minX;
396   m_maxY = maxX;
397   m_minX = minX;
398   m_maxY = maxY;
399 }
400
401 bool
402 Array2dFile::headerRead (frnetorderstream& fs)
403 {
404   if (! fs) {
405     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
406     return false;
407   }
408   
409   fs.seekg (0);
410   kuint16 file_signature;
411   
412   fs.readInt16 (m_headersize);
413   fs.readInt16 (file_signature);
414   fs.readInt16 (m_pixelFormat);
415   fs.readInt16 (m_pixelSize);
416   fs.readInt16 (m_numFileLabels);
417   fs.readInt32 (m_nx);
418   fs.readInt32 (m_ny);
419   fs.readInt16 (m_dataType);
420   fs.readInt16 (m_axisIncrementKnown);
421   fs.readFloat64 (m_axisIncrementX);
422   fs.readFloat64 (m_axisIncrementY);
423   fs.readInt16 (m_axisExtentKnown);
424   fs.readFloat64 (m_minX);
425   fs.readFloat64 (m_maxX);
426   fs.readFloat64 (m_minY);
427   fs.readFloat64 (m_maxY);
428   fs.readFloat64 (m_offsetPV);
429   fs.readFloat64 (m_scalePV);
430   
431   int read_m_headersize = fs.tellg();
432   if (read_m_headersize != m_headersize) {
433     sys_error (ERR_WARNING, "Read m_headersize %d != file m_headersize %d", read_m_headersize, m_headersize);
434     return false;
435   }
436   if (file_signature != m_signature) {
437     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, m_signature);
438     return false;
439   }
440   
441   return ! fs.fail();
442 }
443
444
445 bool
446 Array2dFile::headerWrite (frnetorderstream& fs)
447 {
448   if (! fs) {
449     sys_error (ERR_WARNING, "Tried to write header with ! fs");
450     return false;
451   }
452   
453   m_numFileLabels = m_labels.size();
454   
455   fs.seekp (0);
456   fs.writeInt16 (m_headersize);
457   fs.writeInt16 (m_signature);
458   fs.writeInt16 (m_pixelFormat);
459   fs.writeInt16 (m_pixelSize);
460   fs.writeInt16 (m_numFileLabels);
461   fs.writeInt32 (m_nx);
462   fs.writeInt32 (m_ny);
463   fs.writeInt16 (m_dataType);
464   fs.writeInt16 (m_axisIncrementKnown);
465   fs.writeFloat64 (m_axisIncrementX);
466   fs.writeFloat64 (m_axisIncrementY);
467   fs.writeInt16 (m_axisExtentKnown);
468   fs.writeFloat64 (m_minX);
469   fs.writeFloat64 (m_maxX);
470   fs.writeFloat64 (m_minY);
471   fs.writeFloat64 (m_maxY);
472   fs.writeFloat64 (m_offsetPV);
473   fs.writeFloat64 (m_scalePV);
474   
475   m_headersize = static_cast<kuint16>(fs.tellp());
476   fs.seekp (0);
477   fs.writeInt16 (m_headersize);
478   
479   return ! fs.fail();
480 }
481
482
483 bool
484 Array2dFile::arrayDataWrite (frnetorderstream& fs)
485 {
486   if (! fs) {
487     sys_error (ERR_WARNING, "Tried to arrayDataWrite with !fs");
488     return false;
489   }
490   
491   if (! m_arrayData) 
492     return false;
493   
494   fs.seekp (m_headersize);
495   int columnSize = m_ny * m_pixelSize;
496   for (unsigned int ix = 0; ix < m_nx; ix++) {
497     unsigned char* ptrColumn = m_arrayData[ix];
498     if (NativeBigEndian()) {
499       for (unsigned int iy = 0; iy < m_ny; iy++) {
500         ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
501         fs.write (reinterpret_cast<const char*>(ptrColumn), m_pixelSize);
502         ptrColumn += m_pixelSize;
503       }
504     } else 
505       fs.write (reinterpret_cast<const char*>(ptrColumn), columnSize);
506   }
507   if (m_dataType == DATA_TYPE_COMPLEX) {
508     for (unsigned int ix = 0; ix < m_nx; ix++) {
509       unsigned char* ptrColumn = m_imaginaryArrayData[ix];
510       if (NativeBigEndian()) {
511         for (unsigned int iy = 0; iy < m_ny; iy++) {
512           ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
513           fs.write (reinterpret_cast<const char*>(ptrColumn), m_pixelSize);
514           ptrColumn += m_pixelSize;
515         }
516       } else 
517         fs.write (reinterpret_cast<const char*>(ptrColumn), columnSize);
518     }
519   }
520   
521   return true;
522 }
523
524
525 bool
526 Array2dFile::arrayDataRead (frnetorderstream& fs)
527 {
528   if (! fs) {
529     sys_error (ERR_WARNING, "Tried to arrayDataRead with ! fs");
530     return false;
531   }
532   
533   if (! m_arrayData)
534     return false;
535   
536   fs.seekg (m_headersize);
537   int columnSize = m_ny * m_pixelSize;
538   for (unsigned int ix = 0; ix < m_nx; ix++) {
539     unsigned char* ptrColumn = m_arrayData[ix];
540     if (NativeBigEndian()) {
541       for (unsigned int iy = 0; iy < m_ny; iy++) {
542         fs.read (reinterpret_cast<char*>(ptrColumn), m_pixelSize);
543         ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
544         ptrColumn += m_pixelSize;
545       } 
546     } else
547       fs.read (reinterpret_cast<char*>(ptrColumn), columnSize);
548   }
549   if (m_dataType == DATA_TYPE_COMPLEX) {
550     for (unsigned int ix = 0; ix < m_nx; ix++) {
551       unsigned char* ptrColumn = m_imaginaryArrayData[ix];
552       if (NativeBigEndian()) {
553         for (unsigned int iy = 0; iy < m_ny; iy++) {
554           fs.read (reinterpret_cast<char*>(ptrColumn), m_pixelSize);
555           ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
556           ptrColumn += m_pixelSize;
557         } 
558       } else
559         fs.read (reinterpret_cast<char*>(ptrColumn), columnSize);
560     }
561   }
562   
563   return true;
564 }
565
566 bool
567 Array2dFile::labelsRead (frnetorderstream& fs)
568 {
569   off_t pos = m_headersize + m_arraySize;
570   fs.seekg (pos);
571   if (fs.fail())
572     return false;
573   
574   for (int i = 0; i < m_numFileLabels; i++) {
575     kuint16 labelType, year, month, day, hour, minute, second;
576     kfloat64 calcTime;
577     
578     fs.readInt16 (labelType);
579     fs.readInt16 (year);
580     fs.readInt16 (month);
581     fs.readInt16 (day);
582     fs.readInt16 (hour);
583     fs.readInt16 (minute);
584     fs.readInt16 (second);
585     fs.readFloat64 (calcTime);
586     
587     kuint16 strLength;
588     fs.readInt16 (strLength);
589     char* pszLabelStr = new char [strLength+1];
590     fs.read (pszLabelStr, strLength);
591     pszLabelStr[strLength] = 0;
592     
593     Array2dFileLabel* pLabel = new Array2dFileLabel (labelType, pszLabelStr, calcTime);
594     delete pszLabelStr;
595     
596     pLabel->setDateTime (year, month, day, hour, minute, second);
597     m_labels.push_back (pLabel);
598   }
599   
600   return true;
601 }
602
603 bool
604 Array2dFile::labelsWrite (frnetorderstream& fs)
605 {
606   off_t pos = m_headersize + m_arraySize;
607   fs.seekp (pos);
608   
609   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
610     const Array2dFileLabel& label = **l;
611     kuint16 labelType = label.getLabelType();
612     kfloat64 calcTime = label.getCalcTime();
613     const char* const labelString = label.getLabelString().c_str();
614     int year, month, day, hour, minute, second;
615     kuint16 yearBuf, monthBuf, dayBuf, hourBuf, minuteBuf, secondBuf;
616     
617     label.getDateTime (year, month, day, hour, minute, second);
618     yearBuf = year; monthBuf = month; dayBuf = day;
619     hourBuf = hour; minuteBuf = minute; secondBuf = second;
620     
621     fs.writeInt16 (labelType);
622     fs.writeInt16 (yearBuf);
623     fs.writeInt16 (monthBuf);
624     fs.writeInt16 (dayBuf);
625     fs.writeInt16 (hourBuf);
626     fs.writeInt16 (minuteBuf);
627     fs.writeInt16 (secondBuf);
628     fs.writeFloat64 (calcTime);
629     kuint16 strlength = strlen (labelString);
630     fs.writeInt16 (strlength);
631     fs.write (labelString, strlength);
632   }
633   
634   return true;
635 }
636
637 void
638 Array2dFile::labelAdd (const char* const lstr, double calc_time)
639 {
640   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
641 }
642
643
644 void
645 Array2dFile::labelAdd (int type, const char* const lstr, double calc_time)
646 {
647   Array2dFileLabel label (type, lstr, calc_time);
648   
649   labelAdd (label);
650 }
651
652
653 void
654 Array2dFile::labelAdd (const Array2dFileLabel& label)
655 {
656   Array2dFileLabel* pLabel = new Array2dFileLabel(label);
657   
658   m_labels.push_back (pLabel);
659 }
660
661 void
662 Array2dFile::labelsCopy (const Array2dFile& copyFile, const char* const pszId)
663 {
664   std::string id;
665   if (pszId)
666     id = pszId;
667   for (unsigned int i = 0; i < copyFile.getNumLabels(); i++) {
668     Array2dFileLabel l (copyFile.labelGet (i));
669     std::string lstr = l.getLabelString();
670     lstr = id + lstr;
671     l.setLabelString (lstr);
672     labelAdd (l);
673   }
674 }
675
676 void 
677 Array2dFile::arrayDataClear (void)
678 {
679   if (m_arrayData) {
680     int columnSize = m_ny * m_pixelSize;
681     for (unsigned int ix = 0; ix < m_nx; ix++)
682       memset (m_arrayData[ix], 0, columnSize);
683   }
684   if (m_imaginaryArrayData) {
685     int columnSize = m_ny * m_pixelSize;
686     for (unsigned int ix = 0; ix < m_nx; ix++)
687       memset (m_arrayData[ix], 0, columnSize);
688   }
689 }
690
691 void
692 Array2dFile::printLabels (std::ostream& os) const
693 {
694   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
695     const Array2dFileLabel& label = **l;
696     
697     label.print (os);
698     os << std::endl;
699   }
700 }
701
702 void
703 Array2dFile::printLabelsBrief (std::ostream& os) const
704 {
705   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
706     const Array2dFileLabel& label = **l;
707     
708     label.printBrief (os);
709   }
710 }
711
712 void
713 Array2dFile::printLabelsBrief (std::ostringstream& os) const
714 {
715   for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
716     const Array2dFileLabel& label = **l;
717     
718     label.printBrief (os);
719   }
720 }
721
722
723 const Array2dFileLabel&
724 Array2dFile::labelGet (int i) const
725 {
726   return *m_labels[i];
727 }