40be226ee82c45ec0f523f41aa4842ff57fd5c4a
[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-2000 Kevin Rosenberg
11 **
12 **  $Id: array2dfile.cpp,v 1.18 2000/12/15 22:07:35 kevin Exp $
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>\r
30 #ifdef MSVC\r
31 typedef long off_t;\r
32 #endif
33
34 using namespace std;
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 string& 
110 Array2dFileLabel::getDateString (void) const
111 {
112   char szDate [128];\r
113   snprintf (szDate, sizeof(szDate), "%2d/%02d/%4d %02d:%02d:%02d",\r
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 (ostream& os) const
143 {
144   if (m_labelType == L_HISTORY) {
145     os << "History: " << endl;
146     os << "  " << m_strLabel << endl;
147     os << "  calc time = " << m_calcTime << " secs" << endl;
148     os << "  Timestamp = " << getDateString() << endl;
149   } else if (m_labelType == L_USER) {
150     os << "Note: " <<  m_strLabel << endl;
151     os << "  Timestamp = %s" << getDateString() << endl;
152   } else {
153     os << "Unknown (" << m_labelType << "): " <<  m_strLabel << endl;
154     os << "  Timestamp = %s" << getDateString() << endl;
155   }
156 }
157
158
159 ///////////////////////////////////////////////////////////////////////////
160 // CLASS IMPLEMENTATION
161 //
162 //     Name: Array2dFile
163 //     Purpose: Array2dFiles
164 ///////////////////////////////////////////////////////////////////////////
165
166
167 Array2dFile::Array2dFile (int x, int y, int pixelSize, int pixelFormat)
168 {
169     init();
170     setArraySize (x, y, pixelSize, pixelFormat);
171 }
172
173 Array2dFile::~Array2dFile (void)
174 {
175     freeArray ();
176     for (labelIterator l = m_labels.begin(); l != m_labels.end(); l++)
177       delete *l;
178 }
179
180 Array2dFile::Array2dFile (void)
181 {
182     init();
183 }
184
185 void
186 Array2dFile::init (void)
187 {
188   m_pixelSize = 0;
189   m_pixelFormat = PIXEL_INVALID;
190   m_arrayData = NULL;
191   m_nx = 0;
192   m_ny = 0;
193   m_headersize = 0;
194   m_axisIncrementKnown = false;
195   m_axisIncrementX = m_axisIncrementY = 0;
196   m_axisExtentKnown = false;
197   m_minX = m_maxX = m_minY = m_maxY = 0;
198   m_offsetPV = 0;
199   m_scalePV = 1;
200 }
201
202
203 void
204 Array2dFile::setArraySize (int x, int y, int pixelSize, int pixelFormat)
205 {
206     m_pixelSize = pixelSize;
207     m_pixelFormat = pixelFormat;
208     setArraySize (x, y);
209 }
210
211 void
212 Array2dFile::setArraySize (int x, int y)
213 {
214     m_nx = x;
215     m_ny = y;
216     allocArray ();
217 }
218
219 void 
220 Array2dFile::allocArray (void)
221 {
222     if (m_arrayData)
223         freeArray();
224
225     m_arraySize = m_nx * m_ny * m_pixelSize;
226     m_arrayData = new unsigned char* [m_nx];
227     
228     int columnBytes = m_ny * m_pixelSize;
229     for (unsigned int i = 0; i < m_nx; i++)
230         m_arrayData[i] = new unsigned char [columnBytes];
231 }
232
233 void 
234 Array2dFile::freeArray (void)
235 {
236     if (m_arrayData) {
237         for (unsigned int i = 0; i < m_nx; i++)
238             delete m_arrayData[i];
239         delete m_arrayData;
240         m_arrayData = NULL;
241     }
242 }
243
244 bool
245 Array2dFile::fileWrite (const string& filename)
246 {
247   return fileWrite (filename.c_str());
248 }
249
250 bool
251 Array2dFile::fileWrite (const char* const filename)
252 {
253     m_filename = filename;
254
255     frnetorderstream fs (m_filename.c_str(), ios::out | ios::in | ios::trunc | ios::binary);
256     if (fs.fail()) {
257         sys_error (ERR_WARNING, "Error opening file %s for writing [fileCreate]", m_filename.c_str());
258       return false;
259     }
260     if (! headerWrite(fs))
261         return false;
262     
263     if (! arrayDataWrite (fs))
264         return false;
265     
266     if (! labelsWrite (fs))
267         return false;
268
269     return true;
270 }
271
272 bool
273 Array2dFile::fileRead (const string& filename)
274 {
275   return fileRead (filename.c_str());
276 }
277
278 bool
279 Array2dFile::fileRead (const char* const filename)
280 {
281     m_filename = filename;
282
283 #ifdef MSVC\r
284     frnetorderstream fs (m_filename.c_str(), ios::out | ios::in | ios::binary);\r
285 #else\r
286     frnetorderstream fs (m_filename.c_str(), ios::out | ios::in | ios::binary | ios::nocreate);\r
287 #endif\r
288     if (fs.fail()) {
289       sys_error (ERR_WARNING, "Unable to open file %s [fileRead]", m_filename.c_str());
290       return false;
291     }
292
293     if (! headerRead(fs))
294       return false;
295     
296     allocArray ();
297     
298     if (! arrayDataRead(fs))
299       return false;;
300
301     if (! labelsRead (fs))
302       return false;
303     
304     return true;
305 }
306
307 void
308 Array2dFile::setAxisIncrement (double incX, double incY)
309 {
310   m_axisIncrementKnown = true;
311   m_axisIncrementX = incX;
312   m_axisIncrementY = incY;
313 }
314
315 void 
316 Array2dFile::setAxisExtent (double minX, double maxX, double minY, double maxY)
317 {
318     m_axisExtentKnown = true;
319     m_minX = minX;
320     m_maxY = maxX;
321     m_minX = minX;
322     m_maxY = maxY;
323 }
324
325 bool
326 Array2dFile::headerRead (frnetorderstream& fs)
327 {
328   if (! fs) {
329     sys_error (ERR_WARNING, "Tried to read header with file closed [headerRead]");
330     return false;
331   }
332
333   fs.seekg (0);
334   kuint16 file_signature;
335
336   fs.readInt16 (m_headersize);
337   fs.readInt16 (file_signature);
338   fs.readInt16 (m_pixelFormat);
339   fs.readInt16 (m_pixelSize);
340   fs.readInt16 (m_numFileLabels);
341   fs.readInt32 (m_nx);
342   fs.readInt32 (m_ny);
343   fs.readInt16 (m_axisIncrementKnown);
344   fs.readFloat64 (m_axisIncrementX);
345   fs.readFloat64 (m_axisIncrementY);
346   fs.readInt16 (m_axisExtentKnown);
347   fs.readFloat64 (m_minX);
348   fs.readFloat64 (m_maxX);
349   fs.readFloat64 (m_minY);
350   fs.readFloat64 (m_maxY);
351   fs.readFloat64 (m_offsetPV);
352   fs.readFloat64 (m_scalePV);
353
354   int read_m_headersize = fs.tellg();
355   if (read_m_headersize != m_headersize) {
356     sys_error (ERR_WARNING, "Read m_headersize %d != file m_headersize %d", read_m_headersize, m_headersize);
357     return false;
358   }
359   if (file_signature != m_signature) {
360     sys_error (ERR_WARNING, "File signature %d != true signature %d", file_signature, m_signature);
361     return false;
362   }
363
364   return true;
365 }
366
367
368 bool
369 Array2dFile::headerWrite (frnetorderstream& fs)
370 {
371   if (! fs) {
372     sys_error (ERR_WARNING, "Tried to write header with ! fs");
373     return false;
374   }
375
376   m_numFileLabels = m_labels.size();
377
378   fs.seekp (0);
379   fs.writeInt16 (m_headersize);
380   fs.writeInt16 (m_signature);
381   fs.writeInt16 (m_pixelFormat);
382   fs.writeInt16 (m_pixelSize);
383   fs.writeInt16 (m_numFileLabels);
384   fs.writeInt32 (m_nx);
385   fs.writeInt32 (m_ny);
386   fs.writeInt16 (m_axisIncrementKnown);
387   fs.writeFloat64 (m_axisIncrementX);
388   fs.writeFloat64 (m_axisIncrementY);
389   fs.writeInt16 (m_axisExtentKnown);
390   fs.writeFloat64 (m_minX);
391   fs.writeFloat64 (m_maxX);
392   fs.writeFloat64 (m_minY);
393   fs.writeFloat64 (m_maxY);
394   fs.writeFloat64 (m_offsetPV);
395   fs.writeFloat64 (m_scalePV);
396
397   m_headersize = static_cast<kuint16>(fs.tellp());
398   fs.seekp (0);
399   fs.writeInt16 (m_headersize);
400   
401   return true;
402 }
403
404
405 bool
406 Array2dFile::arrayDataWrite (frnetorderstream& fs)
407 {
408   if (! fs) {
409     sys_error (ERR_WARNING, "Tried to arrayDataWrite with !fs");
410     return false;
411   }
412
413   if (! m_arrayData) 
414       return false;
415
416   fs.seekp (m_headersize);
417   int columnSize = m_ny * m_pixelSize;
418   for (unsigned int ix = 0; ix < m_nx; ix++) {
419       unsigned char* ptrColumn = m_arrayData[ix];
420       if (NativeBigEndian()) {
421           for (unsigned int iy = 0; iy < m_ny; iy++) {
422               ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
423               fs.write (reinterpret_cast<const char*>(ptrColumn), m_pixelSize);
424               ptrColumn += m_pixelSize;
425           }
426       } else 
427           fs.write (reinterpret_cast<const char*>(ptrColumn), columnSize);
428   }
429
430   return true;
431 }
432
433
434 bool
435 Array2dFile::arrayDataRead (frnetorderstream& fs)
436 {
437   if (! fs) {
438     sys_error (ERR_WARNING, "Tried to arrayDataRead with ! fs");
439     return false;
440   }
441
442   if (! m_arrayData)
443       return false;
444
445   fs.seekg (m_headersize);
446   int columnSize = m_ny * m_pixelSize;
447   for (unsigned int ix = 0; ix < m_nx; ix++) {
448       unsigned char* ptrColumn = m_arrayData[ix];
449       if (NativeBigEndian()) {
450           for (unsigned int iy = 0; iy < m_ny; iy++) {
451               fs.read (reinterpret_cast<char*>(ptrColumn), m_pixelSize);
452               ConvertReverseNetworkOrder (ptrColumn, m_pixelSize);
453               ptrColumn += m_pixelSize;
454           } 
455       } else
456           fs.read (reinterpret_cast<char*>(ptrColumn), columnSize);
457   }
458
459   return true;
460 }
461
462 bool
463 Array2dFile::labelsRead (frnetorderstream& fs)
464 {
465     off_t pos = m_headersize + m_arraySize;
466     fs.seekg (pos);
467     if (fs.fail())
468         return false;
469
470     for (int i = 0; i < m_numFileLabels; i++) {
471         kuint16 labelType, year, month, day, hour, minute, second;
472         kfloat64 calcTime;
473
474         fs.readInt16 (labelType);
475         fs.readInt16 (year);
476         fs.readInt16 (month);
477         fs.readInt16 (day);
478         fs.readInt16 (hour);
479         fs.readInt16 (minute);
480         fs.readInt16 (second);
481         fs.readFloat64 (calcTime);
482         
483         kuint16 strLength;
484         fs.readInt16 (strLength);
485         char* pszLabelStr = new char [strLength+1];
486         fs.read (pszLabelStr, strLength);
487         pszLabelStr[strLength] = 0;
488
489         Array2dFileLabel* pLabel = new Array2dFileLabel (labelType, pszLabelStr, calcTime);
490         delete pszLabelStr;\r
491 \r
492         pLabel->setDateTime (year, month, day, hour, minute, second);
493         m_labels.push_back (pLabel);\r
494     }
495
496     return true;
497 }
498
499 bool
500 Array2dFile::labelsWrite (frnetorderstream& fs)
501 {
502     off_t pos = m_headersize + m_arraySize;
503     fs.seekp (pos);
504
505     for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
506         const Array2dFileLabel& label = **l;
507         kuint16 labelType = label.getLabelType();
508         kfloat64 calcTime = label.getCalcTime();
509         const char* const labelString = label.getLabelString().c_str();
510         int year, month, day, hour, minute, second;
511         kuint16 yearBuf, monthBuf, dayBuf, hourBuf, minuteBuf, secondBuf;
512
513         label.getDateTime (year, month, day, hour, minute, second);
514         yearBuf = year; monthBuf = month; dayBuf = day;
515         hourBuf = hour; minuteBuf = minute; secondBuf = second;
516
517         fs.writeInt16 (labelType);
518         fs.writeInt16 (yearBuf);
519         fs.writeInt16 (monthBuf);
520         fs.writeInt16 (dayBuf);
521         fs.writeInt16 (hourBuf);
522         fs.writeInt16 (minuteBuf);
523         fs.writeInt16 (secondBuf);
524         fs.writeFloat64 (calcTime);
525         kuint16 strlength = strlen (labelString);
526         fs.writeInt16 (strlength);
527         fs.write (labelString, strlength);
528     }
529
530     return true;
531 }
532
533 void
534 Array2dFile::labelAdd (const char* const lstr, double calc_time)
535 {
536   labelAdd (Array2dFileLabel::L_HISTORY, lstr, calc_time);
537 }
538
539
540 void
541 Array2dFile::labelAdd (int type, const char* const lstr, double calc_time)
542 {
543   Array2dFileLabel label (type, lstr, calc_time);
544
545   labelAdd (label);
546 }
547
548
549 void
550 Array2dFile::labelAdd (const Array2dFileLabel& label)
551 {
552     Array2dFileLabel* pLabel = new Array2dFileLabel(label);
553
554     m_labels.push_back (pLabel);
555 }
556
557 void
558 Array2dFile::labelsCopy (Array2dFile& copyFile, const char* const pszId)
559 {
560     string id;
561     if (pszId)
562       id = pszId;
563     for (unsigned int i = 0; i < copyFile.getNumLabels(); i++) {
564       Array2dFileLabel l (copyFile.labelGet (i));
565       string lstr = l.getLabelString();
566       lstr = idStr + lstr;
567       l.setLabelString (lstr);
568       labelAdd (l);
569     }
570 }
571
572 void 
573 Array2dFile::arrayDataClear (void)
574 {
575     if (m_arrayData) {
576         int columnSize = m_ny * m_pixelSize;
577         for (unsigned int ix = 0; ix < m_nx; ix++)
578             memset (m_arrayData[ix], 0, columnSize);
579     }
580 }
581
582 void
583 Array2dFile::printLabels (ostream& os) const
584 {
585     for (constLabelIterator l = m_labels.begin(); l != m_labels.end(); l++) {
586       const Array2dFileLabel& label = **l;
587
588       label.print (os);
589       os << endl;
590     }
591 }
592
593
594 const Array2dFileLabel&
595 Array2dFile::labelGet (int i) const
596 {
597   return *m_labels[i];
598 }