File: | src/fits/GFitsTableBitCol.cpp |
Location: | line 941, column 20 |
Description: | Array access (via field 'm_data') results in a null pointer dereference |
1 | /*************************************************************************** | |||
2 | * GFitsTableBitCol.cpp - FITS table Bit column class * | |||
3 | * ----------------------------------------------------------------------- * | |||
4 | * copyright (C) 2008-2013 by Juergen Knoedlseder * | |||
5 | * ----------------------------------------------------------------------- * | |||
6 | * * | |||
7 | * This program is free software: you can redistribute it and/or modify * | |||
8 | * it under the terms of the GNU General Public License as published by * | |||
9 | * the Free Software Foundation, either version 3 of the License, or * | |||
10 | * (at your option) any later version. * | |||
11 | * * | |||
12 | * This program is distributed in the hope that it will be useful, * | |||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |||
15 | * GNU General Public License for more details. * | |||
16 | * * | |||
17 | * You should have received a copy of the GNU General Public License * | |||
18 | * along with this program. If not, see <http://www.gnu.org/licenses/>. * | |||
19 | * * | |||
20 | ***************************************************************************/ | |||
21 | /** | |||
22 | * @file GFitsTableBitCol.cpp | |||
23 | * @brief FITS table bit column class implementation | |||
24 | * @author Juergen Knoedlseder | |||
25 | */ | |||
26 | ||||
27 | /* __ Includes ___________________________________________________________ */ | |||
28 | #ifdef HAVE_CONFIG_H1 | |||
29 | #include <config.h> | |||
30 | #endif | |||
31 | #include <string> | |||
32 | #include "GException.hpp" | |||
33 | #include "GTools.hpp" | |||
34 | #include "GFitsCfitsio.hpp" | |||
35 | #include "GFitsTableBitCol.hpp" | |||
36 | ||||
37 | /* __ Method name definitions ____________________________________________ */ | |||
38 | #define G_INSERT"GFitsTableBitCol::insert(int&, int&)" "GFitsTableBitCol::insert(int&, int&)" | |||
39 | #define G_REMOVE"GFitsTableBitCol::remove(int&, int&)" "GFitsTableBitCol::remove(int&, int&)" | |||
40 | #define G_LOAD_COLUMN"GFitsTableBitCol::load_column()" "GFitsTableBitCol::load_column()" | |||
41 | #define G_SAVE_COLUMN"GFitsTableBitCol::save_column()" "GFitsTableBitCol::save_column()" | |||
42 | #define G_GET_BIT"GFitsTableBitCol::get_bit(int&,int&)" "GFitsTableBitCol::get_bit(int&,int&)" | |||
43 | ||||
44 | /* __ Macros _____________________________________________________________ */ | |||
45 | ||||
46 | /* __ Coding definitions _________________________________________________ */ | |||
47 | ||||
48 | /* __ Debug definitions __________________________________________________ */ | |||
49 | //#define G_CALL_GRAPH //!< Dump call graph in console | |||
50 | ||||
51 | ||||
52 | /*========================================================================== | |||
53 | = = | |||
54 | = Constructors/destructors = | |||
55 | = = | |||
56 | ==========================================================================*/ | |||
57 | ||||
58 | /***********************************************************************//** | |||
59 | * @brief Constructor | |||
60 | ***************************************************************************/ | |||
61 | GFitsTableBitCol::GFitsTableBitCol(void) : GFitsTableCol() | |||
62 | { | |||
63 | // Initialise class members for clean destruction | |||
64 | init_members(); | |||
65 | ||||
66 | // Return | |||
67 | return; | |||
68 | } | |||
69 | ||||
70 | ||||
71 | /***********************************************************************//** | |||
72 | * @brief Constructor | |||
73 | * | |||
74 | * @param[in] name Name of column. | |||
75 | * @param[in] length Length of column. | |||
76 | * @param[in] size Vector size of column. | |||
77 | ***************************************************************************/ | |||
78 | GFitsTableBitCol::GFitsTableBitCol(const std::string& name, | |||
79 | const int& length, | |||
80 | const int& size) : | |||
81 | GFitsTableCol(name, length, size, 1) | |||
82 | { | |||
83 | // Initialise class members for clean destruction | |||
84 | init_members(); | |||
85 | ||||
86 | // Return | |||
87 | return; | |||
88 | } | |||
89 | ||||
90 | ||||
91 | /***********************************************************************//** | |||
92 | * @brief Copy constructor | |||
93 | * | |||
94 | * @param[in] column Table column. | |||
95 | ***************************************************************************/ | |||
96 | GFitsTableBitCol::GFitsTableBitCol(const GFitsTableBitCol& column) : | |||
97 | GFitsTableCol(column) | |||
98 | { | |||
99 | // Initialise class members for clean destruction | |||
100 | init_members(); | |||
101 | ||||
102 | // Copy members | |||
103 | copy_members(column); | |||
104 | ||||
105 | // Return | |||
106 | return; | |||
107 | } | |||
108 | ||||
109 | ||||
110 | /***********************************************************************//** | |||
111 | * @brief Destructor | |||
112 | ***************************************************************************/ | |||
113 | GFitsTableBitCol::~GFitsTableBitCol(void) | |||
114 | { | |||
115 | // Free members | |||
116 | free_members(); | |||
117 | ||||
118 | // Return | |||
119 | return; | |||
120 | } | |||
121 | ||||
122 | ||||
123 | /*========================================================================== | |||
124 | = = | |||
125 | = Operators = | |||
126 | = = | |||
127 | ==========================================================================*/ | |||
128 | ||||
129 | /***********************************************************************//** | |||
130 | * @brief Assignment operator | |||
131 | * | |||
132 | * @param[in] column Table column. | |||
133 | * @return Table column. | |||
134 | ***************************************************************************/ | |||
135 | GFitsTableBitCol& GFitsTableBitCol::operator=(const GFitsTableBitCol& column) | |||
136 | { | |||
137 | // Execute only if object is not identical | |||
138 | if (this != &column) { | |||
139 | ||||
140 | // Copy base class members | |||
141 | this->GFitsTableCol::operator=(column); | |||
142 | ||||
143 | // Free members | |||
144 | free_members(); | |||
145 | ||||
146 | // Initialise private members for clean destruction | |||
147 | init_members(); | |||
148 | ||||
149 | // Copy members | |||
150 | copy_members(column); | |||
151 | ||||
152 | } // endif: object was not identical | |||
153 | ||||
154 | // Return this object | |||
155 | return *this; | |||
156 | } | |||
157 | ||||
158 | ||||
159 | /***********************************************************************//** | |||
160 | * @brief Column data access operator | |||
161 | * | |||
162 | * @param[in] row Row of column to access. | |||
163 | * @param[in] inx Vector index in column row to access. | |||
164 | * | |||
165 | * Provides access to data in a column. | |||
166 | ***************************************************************************/ | |||
167 | bool& GFitsTableBitCol::operator()(const int& row, const int& inx) | |||
168 | { | |||
169 | // If data are not available then load them now | |||
170 | if (m_data == NULL__null) this->fetch_data(); | |||
171 | ||||
172 | // Set any pending Bit | |||
173 | set_pending(); | |||
174 | ||||
175 | // Get Bit | |||
176 | get_bit(row, inx); | |||
177 | ||||
178 | // Signal that a Bit is pending. We need this here since the non-const | |||
179 | // operator allows changing the Bit after exiting the method, hence | |||
180 | // we have to signal that the actual value of 'm_bit_value' could have | |||
181 | // been modified and needs to be written back into the data array. | |||
182 | m_bit_pending = true; | |||
183 | ||||
184 | // Return Bit | |||
185 | return m_bit_value; | |||
186 | } | |||
187 | ||||
188 | ||||
189 | /***********************************************************************//** | |||
190 | * @brief Column data access operator (const variant) | |||
191 | * | |||
192 | * @param[in] row Row of column to access. | |||
193 | * @param[in] inx Vector index in column row to access | |||
194 | * | |||
195 | * Provides access to data in a column. | |||
196 | ***************************************************************************/ | |||
197 | const bool& GFitsTableBitCol::operator()(const int& row, const int& inx) const | |||
198 | { | |||
199 | // Circumvent const correctness | |||
200 | GFitsTableBitCol* ptr = const_cast<GFitsTableBitCol*>(this); | |||
201 | ||||
202 | // If data are not available then load them now | |||
203 | if (m_data == NULL__null) ptr->fetch_data(); | |||
204 | ||||
205 | // Set any pending Bit | |||
206 | ptr->set_pending(); | |||
207 | ||||
208 | // Get Bit | |||
209 | ptr->get_bit(row, inx); | |||
210 | ||||
211 | // Return data bin | |||
212 | return m_bit_value; | |||
213 | } | |||
214 | ||||
215 | ||||
216 | /*========================================================================== | |||
217 | = = | |||
218 | = Public methods = | |||
219 | = = | |||
220 | ==========================================================================*/ | |||
221 | ||||
222 | /***********************************************************************//** | |||
223 | * @brief Clear instance | |||
224 | * | |||
225 | * This method properly resets the object to an initial state. | |||
226 | ***************************************************************************/ | |||
227 | void GFitsTableBitCol::clear(void) | |||
228 | { | |||
229 | // Free class members (base and derived classes, derived class first) | |||
230 | free_members(); | |||
231 | this->GFitsTableCol::free_members(); | |||
232 | ||||
233 | // Initialise members | |||
234 | this->GFitsTableCol::init_members(); | |||
235 | init_members(); | |||
236 | ||||
237 | // Return | |||
238 | return; | |||
239 | } | |||
240 | ||||
241 | ||||
242 | /***********************************************************************//** | |||
243 | * @brief Clone column | |||
244 | ***************************************************************************/ | |||
245 | GFitsTableBitCol* GFitsTableBitCol::clone(void) const | |||
246 | { | |||
247 | return new GFitsTableBitCol(*this); | |||
248 | } | |||
249 | ||||
250 | ||||
251 | /***********************************************************************//** | |||
252 | * @brief Get string value | |||
253 | * | |||
254 | * @param[in] row Table row. | |||
255 | * @param[in] inx Table column vector index. | |||
256 | * | |||
257 | * Returns value of specified row and vector index as string. | |||
258 | ***************************************************************************/ | |||
259 | std::string GFitsTableBitCol::string(const int& row, const int& inx) const | |||
260 | { | |||
261 | // Get Bit value | |||
262 | bool bit = (*this)(row, inx); | |||
263 | ||||
264 | // Convert bit into string | |||
265 | std::string result = (bit) ? "T" : "F"; | |||
266 | ||||
267 | // Return result | |||
268 | return result; | |||
269 | } | |||
270 | ||||
271 | ||||
272 | /***********************************************************************//** | |||
273 | * @brief Get double precision value | |||
274 | * | |||
275 | * @param[in] row Table row. | |||
276 | * @param[in] inx Table column vector index. | |||
277 | * | |||
278 | * Returns value of specified row and vector index as double precision. | |||
279 | ***************************************************************************/ | |||
280 | double GFitsTableBitCol::real(const int& row, const int& inx) const | |||
281 | { | |||
282 | // Get Bit value | |||
283 | bool bit = (*this)(row, inx); | |||
284 | ||||
285 | // Convert bit into double | |||
286 | double result = (bit) ? 1.0 : 0.0; | |||
287 | ||||
288 | // Return result | |||
289 | return result; | |||
290 | } | |||
291 | ||||
292 | ||||
293 | /***********************************************************************//** | |||
294 | * @brief Get integer value | |||
295 | * | |||
296 | * @param[in] row Table row. | |||
297 | * @param[in] inx Table column vector index. | |||
298 | * | |||
299 | * Returns value of specified row and vector index as integer. | |||
300 | ***************************************************************************/ | |||
301 | int GFitsTableBitCol::integer(const int& row, const int& inx) const | |||
302 | { | |||
303 | // Get Bit value | |||
304 | bool bit = (*this)(row, inx); | |||
| ||||
305 | ||||
306 | // Convert bit into double | |||
307 | int result = (bit) ? 1 : 0; | |||
308 | ||||
309 | // Return result | |||
310 | return result; | |||
311 | } | |||
312 | ||||
313 | ||||
314 | /***********************************************************************//** | |||
315 | * @brief Insert rows in column | |||
316 | * | |||
317 | * @param[in] row Row after which rows should be inserted (0=first row). | |||
318 | * @param[in] nrows Number of rows to be inserted. | |||
319 | * | |||
320 | * @exception GException::fits_invalid_row | |||
321 | * Specified row is invalid. | |||
322 | * | |||
323 | * This method inserts rows into a FITS table. This implies that the column | |||
324 | * will be loaded into memory. | |||
325 | ***************************************************************************/ | |||
326 | void GFitsTableBitCol::insert(const int& row, const int& nrows) | |||
327 | { | |||
328 | // Make sure that row is valid | |||
329 | if (row < 0 || row > m_length) { | |||
330 | throw GException::fits_invalid_row(G_INSERT"GFitsTableBitCol::insert(int&, int&)", row, m_length); | |||
331 | } | |||
332 | ||||
333 | // Continue only if there are rows to be inserted | |||
334 | if (nrows > 0) { | |||
335 | ||||
336 | // If we have no rows yet then simply set the length to the | |||
337 | // number of rows to be inserted | |||
338 | if (m_length == 0) { | |||
339 | m_length = nrows; | |||
340 | } | |||
341 | ||||
342 | // ... otherwise fetch data, allocate new data and copy over | |||
343 | // the existing items | |||
344 | else { | |||
345 | ||||
346 | // If data are not available then load them now | |||
347 | if (m_data == NULL__null) fetch_data(); | |||
348 | ||||
349 | // Set any pending Bit | |||
350 | set_pending(); | |||
351 | ||||
352 | // Compute new column length | |||
353 | int length = m_length + nrows; | |||
354 | ||||
355 | // Compute total number of Bits in column | |||
356 | m_bits = m_number * length; | |||
357 | ||||
358 | // Compute number of Bytes and Bits per row | |||
359 | m_bytes_per_row = (m_number > 0) ? ((m_number-1) / 8) + 1 : 0; | |||
360 | m_bits_per_row = m_bytes_per_row * 8; | |||
361 | ||||
362 | // Compute length of memory array | |||
363 | m_size = m_bytes_per_row * length; | |||
364 | ||||
365 | // Allocate new data to hold the column | |||
366 | unsigned char* new_data = new unsigned char[m_size]; | |||
367 | ||||
368 | // Compute the number of elements before the insertion point, | |||
369 | // the number of elements that get inserted, and the total | |||
370 | // number of elements after the insertion point | |||
371 | int n_before = m_bytes_per_row * row; | |||
372 | int n_insert = m_bytes_per_row * nrows; | |||
373 | int n_after = m_bytes_per_row * (m_length - row); | |||
374 | ||||
375 | // Copy and initialise data | |||
376 | unsigned char* src = m_data; | |||
377 | unsigned char* dst = new_data; | |||
378 | for (int i = 0; i < n_before; ++i) { | |||
379 | *dst++ = *src++; | |||
380 | } | |||
381 | for (int i = 0; i < n_insert; ++i) { | |||
382 | *dst++ = 0; | |||
383 | } | |||
384 | for (int i = 0; i < n_after; ++i) { | |||
385 | *dst++ = *src++; | |||
386 | } | |||
387 | ||||
388 | // Free old data | |||
389 | if (m_data != NULL__null) delete [] m_data; | |||
390 | ||||
391 | // Set pointer to new data and store length | |||
392 | m_data = new_data; | |||
393 | m_length = length; | |||
394 | ||||
395 | } // endelse: there were already data | |||
396 | ||||
397 | } // endfor: there were rows to be inserted | |||
398 | ||||
399 | // Return | |||
400 | return; | |||
401 | } | |||
402 | ||||
403 | ||||
404 | /***********************************************************************//** | |||
405 | * @brief Remove rows from column | |||
406 | * | |||
407 | * @param[in] row Row after which rows should be removed (0=first row). | |||
408 | * @param[in] nrows Number of rows to be removed. | |||
409 | * | |||
410 | * @exception GException::fits_invalid_row | |||
411 | * Specified row is invalid. | |||
412 | * @exception GException::fits_invalid_nrows | |||
413 | * Invalid number of rows specified. | |||
414 | * | |||
415 | * This method removes rows from a FITS table. This implies that the column | |||
416 | * will be loaded into memory. | |||
417 | ***************************************************************************/ | |||
418 | void GFitsTableBitCol::remove(const int& row, const int& nrows) | |||
419 | { | |||
420 | // Make sure that row is valid | |||
421 | if (row < 0 || row >= m_length) { | |||
422 | throw GException::fits_invalid_row(G_REMOVE"GFitsTableBitCol::remove(int&, int&)", row, m_length-1); | |||
423 | } | |||
424 | ||||
425 | // Make sure that we don't remove beyond the limit | |||
426 | if (nrows < 0 || nrows > m_length-row) { | |||
427 | throw GException::fits_invalid_nrows(G_REMOVE"GFitsTableBitCol::remove(int&, int&)", nrows, m_length-row); | |||
428 | } | |||
429 | ||||
430 | // Continue only if there are rows to be removed | |||
431 | if (nrows > 0) { | |||
432 | ||||
433 | // If data are not available then load them now | |||
434 | if (m_data == NULL__null) fetch_data(); | |||
435 | ||||
436 | // Set any pending Bit | |||
437 | set_pending(); | |||
438 | ||||
439 | // Compute new column length | |||
440 | int length = m_length - nrows; | |||
441 | ||||
442 | // Compute total number of Bits in column | |||
443 | m_bits = m_number * length; | |||
444 | ||||
445 | // Compute number of Bytes and Bits per row | |||
446 | m_bytes_per_row = (m_number > 0) ? ((m_number-1) / 8) + 1 : 0; | |||
447 | m_bits_per_row = m_bytes_per_row * 8; | |||
448 | ||||
449 | // Compute length of memory array | |||
450 | m_size = m_bytes_per_row * length; | |||
451 | ||||
452 | // If we have rows remaining then allocate new data to hold | |||
453 | // the column | |||
454 | if (m_size > 0) { | |||
455 | ||||
456 | // Allocate new data to hold the column | |||
457 | unsigned char* new_data = new unsigned char[m_size]; | |||
458 | ||||
459 | // Compute the number of elements before the removal point, | |||
460 | // the number of elements that get removed, and the total | |||
461 | // number of elements after the removal point | |||
462 | int n_before = m_bytes_per_row * row; | |||
463 | int n_remove = m_bytes_per_row * nrows; | |||
464 | int n_after = m_bytes_per_row * (length - row); | |||
465 | ||||
466 | // Copy data | |||
467 | unsigned char* src = m_data; | |||
468 | unsigned char* dst = new_data; | |||
469 | for (int i = 0; i < n_before; ++i) { | |||
470 | *dst++ = *src++; | |||
471 | } | |||
472 | src += n_remove; | |||
473 | for (int i = 0; i < n_after; ++i) { | |||
474 | *dst++ = *src++; | |||
475 | } | |||
476 | ||||
477 | // Free old data | |||
478 | if (m_data != NULL__null) delete [] m_data; | |||
479 | ||||
480 | // Set pointer to new data and store length | |||
481 | m_data = new_data; | |||
482 | m_length = length; | |||
483 | ||||
484 | } // endif: there are still elements after removal | |||
485 | ||||
486 | // ... otherwise just remove all data | |||
487 | else { | |||
488 | ||||
489 | // Free old data | |||
490 | if (m_data != NULL__null) delete [] m_data; | |||
491 | ||||
492 | // Set pointer to new data and store length | |||
493 | m_data = NULL__null; | |||
494 | m_length = length; | |||
495 | } | |||
496 | ||||
497 | } // endfor: there were rows to be removed | |||
498 | ||||
499 | // Return | |||
500 | return; | |||
501 | } | |||
502 | ||||
503 | ||||
504 | /***********************************************************************//** | |||
505 | * @brief Set nul value | |||
506 | * | |||
507 | * @param[in] value Nul value. | |||
508 | * | |||
509 | * @todo To correctly reflect the nul value in the data, the column should | |||
510 | * be reloaded. However, the column may have been changed, so in principle | |||
511 | * saving is needed. However, we may not want to store the data, hence saving | |||
512 | * is also not desired. We thus have to develop a method to update the | |||
513 | * column information for a new nul value in place ... | |||
514 | ***************************************************************************/ | |||
515 | void GFitsTableBitCol::nulval(const unsigned char* value) | |||
516 | { | |||
517 | // Allocate nul value | |||
518 | alloc_nulval(value); | |||
519 | ||||
520 | // Update column | |||
521 | // if (m_data != NULL) { | |||
522 | // save(); | |||
523 | // load(); | |||
524 | // } | |||
525 | ||||
526 | // Return | |||
527 | return; | |||
528 | } | |||
529 | ||||
530 | ||||
531 | /*========================================================================== | |||
532 | = = | |||
533 | = Private methods = | |||
534 | = = | |||
535 | ==========================================================================*/ | |||
536 | ||||
537 | /***********************************************************************//** | |||
538 | * @brief Initialise class members | |||
539 | ***************************************************************************/ | |||
540 | void GFitsTableBitCol::init_members(void) | |||
541 | { | |||
542 | // Optionally print call graph | |||
543 | #if defined(G_CALL_GRAPH) | |||
544 | printf("GFitsTableBitCol::init_members\n"); | |||
545 | #endif | |||
546 | ||||
547 | // Initialise members | |||
548 | m_type = __TBIT1; | |||
549 | m_bits = 0; | |||
550 | m_bytes_per_row = 0; | |||
551 | m_bits_per_row = 0; | |||
552 | m_data = NULL__null; | |||
553 | m_nulval = NULL__null; | |||
554 | m_bit_pending = false; | |||
555 | m_bit_value = false; | |||
556 | m_bit_byte = 0; | |||
557 | m_bit_mask = 0; | |||
558 | ||||
559 | // Optionally print call graph | |||
560 | #if defined(G_CALL_GRAPH) | |||
561 | printf("exit GFitsTableBitCol::init_members\n"); | |||
562 | #endif | |||
563 | ||||
564 | // Return | |||
565 | return; | |||
566 | } | |||
567 | ||||
568 | ||||
569 | /***********************************************************************//** | |||
570 | * @brief Copy class members | |||
571 | * | |||
572 | * @param[in] column Column. | |||
573 | * | |||
574 | * Sets the content of the vector column by copying from another column. | |||
575 | * If the code is compiled with the small memory option, and if the source | |||
576 | * column has not yet been loaded, then we only load the column temporarily | |||
577 | * for copying purposes and release it again once copying is finished. | |||
578 | ***************************************************************************/ | |||
579 | void GFitsTableBitCol::copy_members(const GFitsTableBitCol& column) | |||
580 | { | |||
581 | // Fetch data if necessary | |||
582 | bool not_loaded = (!column.isloaded()); | |||
583 | if (not_loaded) { | |||
584 | column.fetch_data(); | |||
585 | } | |||
586 | ||||
587 | // Copy attributes | |||
588 | m_type = column.m_type; | |||
589 | m_size = column.m_size; | |||
590 | m_varlen = column.m_varlen; | |||
591 | m_rowstart = column.m_rowstart; | |||
592 | m_bits = column.m_bits; | |||
593 | m_bytes_per_row = column.m_bytes_per_row; | |||
594 | m_bits_per_row = column.m_bits_per_row; | |||
595 | m_bit_pending = column.m_bit_pending; | |||
596 | m_bit_value = column.m_bit_value; | |||
597 | m_bit_byte = column.m_bit_byte; | |||
598 | m_bit_mask = column.m_bit_mask; | |||
599 | ||||
600 | // Copy column data | |||
601 | if (column.m_data != NULL__null && m_size > 0) { | |||
602 | alloc_data(); | |||
603 | for (int i = 0; i < m_size; ++i) | |||
604 | m_data[i] = column.m_data[i]; | |||
605 | } | |||
606 | ||||
607 | // Copy NULL value | |||
608 | alloc_nulval(column.m_nulval); | |||
609 | ||||
610 | // Small memory option: release column if it was fetch above | |||
611 | #if defined(G_SMALL_MEMORY1) | |||
612 | if (not_loaded) { | |||
613 | const_cast<GFitsTableBitCol*>(&column)->release_data(); | |||
614 | } | |||
615 | #endif | |||
616 | ||||
617 | // Return | |||
618 | return; | |||
619 | } | |||
620 | ||||
621 | ||||
622 | /***********************************************************************//** | |||
623 | * @brief Delete class members | |||
624 | ***************************************************************************/ | |||
625 | void GFitsTableBitCol::free_members(void) | |||
626 | { | |||
627 | // Optionally print call graph | |||
628 | #if defined(G_CALL_GRAPH) | |||
629 | printf("GFitsTableBitCol::free_members\n"); | |||
630 | #endif | |||
631 | ||||
632 | // Free memory | |||
633 | if (m_data != NULL__null) delete [] m_data; | |||
634 | if (m_nulval != NULL__null) delete m_nulval; | |||
635 | ||||
636 | // Mark memory as freed | |||
637 | m_data = NULL__null; | |||
638 | m_nulval = NULL__null; | |||
639 | ||||
640 | // Reset load flag | |||
641 | m_size = 0; | |||
642 | ||||
643 | // Optionally print call graph | |||
644 | #if defined(G_CALL_GRAPH) | |||
645 | printf("exit GFitsTableBitCol::free_members\n"); | |||
646 | #endif | |||
647 | ||||
648 | // Return | |||
649 | return; | |||
650 | } | |||
651 | ||||
652 | ||||
653 | /***********************************************************************//** | |||
654 | * @brief Returns format string of ASCII table | |||
655 | ***************************************************************************/ | |||
656 | std::string GFitsTableBitCol::ascii_format(void) const | |||
657 | { | |||
658 | // Initialize format string | |||
659 | std::string format; | |||
660 | ||||
661 | // Set type code | |||
662 | format.append("I"); | |||
663 | ||||
664 | // Set width | |||
665 | format.append(gammalib::str(m_width)); | |||
666 | ||||
667 | // Return format | |||
668 | return format; | |||
669 | } | |||
670 | ||||
671 | ||||
672 | /***********************************************************************//** | |||
673 | * @brief Allocates column data | |||
674 | ***************************************************************************/ | |||
675 | void GFitsTableBitCol::alloc_data(void) | |||
676 | { | |||
677 | // Optionally print call graph | |||
678 | #if defined(G_CALL_GRAPH) | |||
679 | printf("GFitsTableBitCol::alloc_data(%d)\n", m_size); | |||
680 | #endif | |||
681 | ||||
682 | // Free any existing memory | |||
683 | if (m_data != NULL__null) delete [] m_data; | |||
684 | ||||
685 | // Mark pointer as free | |||
686 | m_data = NULL__null; | |||
687 | ||||
688 | // Allocate new data | |||
689 | if (m_size > 0) { | |||
690 | m_data = new unsigned char[m_size]; | |||
691 | } | |||
692 | ||||
693 | // Optionally print call graph | |||
694 | #if defined(G_CALL_GRAPH) | |||
695 | printf("exit GFitsTableBitCol::alloc_data(m_data=%x)\n", m_data); | |||
696 | #endif | |||
697 | ||||
698 | // Return | |||
699 | return; | |||
700 | } | |||
701 | ||||
702 | ||||
703 | /***********************************************************************//** | |||
704 | * @brief Fetch column data | |||
705 | * | |||
706 | * This method fetches column data when needed. It is declared const, so | |||
707 | * that const data access methods can be implemented. | |||
708 | * | |||
709 | * If a FITS file is attached to the column the data are loaded into memory | |||
710 | * from the FITS file. If no FITS file is attached, memory is allocated | |||
711 | * to hold the column data and all cells are initialised. | |||
712 | * | |||
713 | * This method calls GFitsTableCol::load_column to do the job. | |||
714 | ***************************************************************************/ | |||
715 | void GFitsTableBitCol::fetch_data(void) const | |||
716 | { | |||
717 | // Load column (circumvent const correctness) | |||
718 | const_cast<GFitsTableBitCol*>(this)->load_column(); | |||
719 | ||||
720 | // Return | |||
721 | return; | |||
722 | } | |||
723 | ||||
724 | ||||
725 | /***********************************************************************//** | |||
726 | * @brief Resize column data | |||
727 | * | |||
728 | * @param[in] index Start index. | |||
729 | * @param[in] number Number of elements to add/remove. | |||
730 | * | |||
731 | * Adds or removes elements from specified index on. Adding is done if | |||
732 | * @p number is a positive number, removing if @p number is negative. | |||
733 | * Note that the method does not change the validity of the arguments. | |||
734 | * This needs to be done by the client. | |||
735 | * | |||
736 | * @todo Needs to be implemented | |||
737 | ***************************************************************************/ | |||
738 | void GFitsTableBitCol::resize_data(const int& index, const int& number) | |||
739 | { | |||
740 | //TODO | |||
741 | ||||
742 | // Return | |||
743 | return; | |||
744 | } | |||
745 | ||||
746 | ||||
747 | /***********************************************************************//** | |||
748 | * @brief Release column data | |||
749 | ***************************************************************************/ | |||
750 | void GFitsTableBitCol::release_data(void) | |||
751 | { | |||
752 | // Free any existing memory | |||
753 | if (m_data != NULL__null) delete [] m_data; | |||
754 | ||||
755 | // Mark pointer as free and reset loaded vector size | |||
756 | m_data = NULL__null; | |||
757 | m_size = 0; | |||
758 | ||||
759 | // Return | |||
760 | return; | |||
761 | } | |||
762 | ||||
763 | ||||
764 | /***********************************************************************//** | |||
765 | * @brief Allocates null value | |||
766 | ***************************************************************************/ | |||
767 | void GFitsTableBitCol::alloc_nulval(const unsigned char* value) | |||
768 | { | |||
769 | // Free any existing memory | |||
770 | if (m_nulval != NULL__null) delete m_nulval; | |||
771 | ||||
772 | // Mark pointer as free | |||
773 | m_nulval = NULL__null; | |||
774 | ||||
775 | // If we have valid value, allocate and set nul value | |||
776 | if (value != NULL__null) { | |||
777 | m_nulval = new unsigned char; | |||
778 | *m_nulval = *value; | |||
779 | } | |||
780 | ||||
781 | // Return | |||
782 | return; | |||
783 | } | |||
784 | ||||
785 | ||||
786 | /***********************************************************************//** | |||
787 | * @brief Initialise column data | |||
788 | ***************************************************************************/ | |||
789 | void GFitsTableBitCol::init_data(void) | |||
790 | { | |||
791 | // Initialise data if they exist | |||
792 | if (m_data != NULL__null) { | |||
793 | for (int i = 0; i < m_size; ++i) { | |||
794 | m_data[i] = 0; | |||
795 | } | |||
796 | } | |||
797 | ||||
798 | // Return | |||
799 | return; | |||
800 | } | |||
801 | ||||
802 | ||||
803 | /***********************************************************************//** | |||
804 | * @brief Load table column from FITS file | |||
805 | * | |||
806 | * @exception GException::fits_hdu_not_found | |||
807 | * Specified HDU not found in FITS file. | |||
808 | * @exception GException::fits_error | |||
809 | * An error occured while loading column data from FITS file. | |||
810 | * | |||
811 | * Load Bit (vector) column into memory by reading 8 Bits at once. | |||
812 | ***************************************************************************/ | |||
813 | void GFitsTableBitCol::load_column(void) | |||
814 | { | |||
815 | // Compute total number of Bits in column | |||
816 | m_bits = m_number * m_length; | |||
817 | ||||
818 | // Compute number of Bytes and Bits per row | |||
819 | m_bytes_per_row = (m_number > 0) ? ((m_number-1) / 8) + 1 : 0; | |||
820 | m_bits_per_row = m_bytes_per_row * 8; | |||
821 | ||||
822 | // Compute length of memory array | |||
823 | m_size = m_bytes_per_row * m_length; | |||
824 | ||||
825 | // Load only if the column has a positive size | |||
826 | if (m_size > 0) { | |||
827 | ||||
828 | // Allocate and initialise fresh memory | |||
829 | alloc_data(); | |||
830 | init_data(); | |||
831 | ||||
832 | // If a FITS file is attached then load column data from the FITS | |||
833 | // file | |||
834 | if (FPTR(m_fitsfile)((__fitsfile*)m_fitsfile)->Fptr != NULL__null) { | |||
835 | ||||
836 | // Move to the HDU | |||
837 | int status = 0; | |||
838 | status = __ffmahd(FPTR(m_fitsfile),ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status) | |||
839 | (FPTR(m_fitsfile)->HDUposition)+1,ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status) | |||
840 | NULL, &status)ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status); | |||
841 | if (status != 0) { | |||
842 | throw GException::fits_hdu_not_found(G_LOAD_COLUMN"GFitsTableBitCol::load_column()", | |||
843 | (FPTR(m_fitsfile)((__fitsfile*)m_fitsfile)->HDUposition)+1, | |||
844 | status); | |||
845 | } | |||
846 | ||||
847 | // Load data 8 Bits at once | |||
848 | status = __ffgcv(FPTR(m_fitsfile), __TBYTE, m_colnum, 1, 1, m_size,ffgcv(((__fitsfile*)m_fitsfile), 11, m_colnum, 1, 1, m_size, m_nulval , m_data, &m_anynul, &status) | |||
849 | m_nulval, m_data, &m_anynul, &status)ffgcv(((__fitsfile*)m_fitsfile), 11, m_colnum, 1, 1, m_size, m_nulval , m_data, &m_anynul, &status); | |||
850 | if (status != 0) { | |||
851 | throw GException::fits_error(G_LOAD_COLUMN"GFitsTableBitCol::load_column()", status, | |||
852 | "for column \""+m_name+"\"."); | |||
853 | } | |||
854 | } | |||
855 | ||||
856 | } // endif: column has a positive size | |||
857 | ||||
858 | // Return | |||
859 | return; | |||
860 | } | |||
861 | ||||
862 | ||||
863 | /***********************************************************************//** | |||
864 | * @brief Save table column into FITS file | |||
865 | * | |||
866 | * @exception GException::fits_hdu_not_found | |||
867 | * Specified HDU not found in FITS file. | |||
868 | * @exception GException::fits_error | |||
869 | * Error occured during writing of the column data. | |||
870 | * | |||
871 | * Save Bit (vector) column into FITS file by writing 8 Bits at once. | |||
872 | ***************************************************************************/ | |||
873 | void GFitsTableBitCol::save_column(void) | |||
874 | { | |||
875 | // Continue only if a FITS file is connected and data have been loaded | |||
876 | if (FPTR(m_fitsfile)((__fitsfile*)m_fitsfile)->Fptr != NULL__null && m_colnum > 0 && m_data != NULL__null) { | |||
877 | ||||
878 | // Set any pending Bit | |||
879 | set_pending(); | |||
880 | ||||
881 | // Move to the HDU | |||
882 | int status = 0; | |||
883 | status = __ffmahd(FPTR(m_fitsfile),ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status) | |||
884 | (FPTR(m_fitsfile)->HDUposition)+1, NULL,ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status) | |||
885 | &status)ffmahd(((__fitsfile*)m_fitsfile), (((__fitsfile*)m_fitsfile)-> HDUposition)+1, __null, &status); | |||
886 | if (status != 0) { | |||
887 | throw GException::fits_hdu_not_found(G_SAVE_COLUMN"GFitsTableBitCol::save_column()", | |||
888 | (FPTR(m_fitsfile)((__fitsfile*)m_fitsfile)->HDUposition)+1, | |||
889 | status); | |||
890 | } | |||
891 | ||||
892 | // Save data 8 Bits at once | |||
893 | status = __ffpcn(FPTR(m_fitsfile), __TBYTE, m_colnum, 1, 1,ffpcn(((__fitsfile*)m_fitsfile), 11, m_colnum, 1, 1, m_size, m_data , m_nulval, &status) | |||
894 | m_size, m_data, m_nulval, &status)ffpcn(((__fitsfile*)m_fitsfile), 11, m_colnum, 1, 1, m_size, m_data , m_nulval, &status); | |||
895 | if (status != 0) { | |||
896 | throw GException::fits_error(G_SAVE_COLUMN"GFitsTableBitCol::save_column()", status); | |||
897 | } | |||
898 | ||||
899 | } // endif: FITS file was connected | |||
900 | ||||
901 | // Return | |||
902 | return; | |||
903 | } | |||
904 | ||||
905 | ||||
906 | /***********************************************************************//** | |||
907 | * @brief Get Bit for boolean access | |||
908 | * | |||
909 | * @param[in] row Row of column. | |||
910 | * @param[in] inx Vector index in column row. | |||
911 | * | |||
912 | * @exception GException::fits_invalid_row | |||
913 | * Table row out of valid range. | |||
914 | * @exception GException::out_of_range | |||
915 | * Table vector index out of valid range. | |||
916 | * | |||
917 | * Set the Bit for boolean data access. Note that this method assumes that | |||
918 | * the data have already been loaded. | |||
919 | ***************************************************************************/ | |||
920 | void GFitsTableBitCol::get_bit(const int& row, const int& inx) | |||
921 | { | |||
922 | // Check row value | |||
923 | #if defined(G_RANGE_CHECK1) | |||
924 | if (row < 0 || row >= m_length) { | |||
925 | throw GException::fits_invalid_row(G_GET_BIT"GFitsTableBitCol::get_bit(int&,int&)", row, m_length-1); | |||
926 | } | |||
927 | #endif | |||
928 | ||||
929 | // Check inx value | |||
930 | #if defined(G_RANGE_CHECK1) | |||
931 | if (inx < 0 || inx >= m_number) { | |||
932 | throw GException::out_of_range(G_GET_BIT"GFitsTableBitCol::get_bit(int&,int&)", inx, 0, m_number-1); | |||
933 | } | |||
934 | #endif | |||
935 | ||||
936 | // Compute Byte and Bit mask | |||
937 | m_bit_byte = row * m_bytes_per_row + inx / 8; | |||
938 | m_bit_mask = 1 << (7 - (inx % 8)); | |||
939 | ||||
940 | // Set Bit value | |||
941 | m_bit_value = (m_data[m_bit_byte] & m_bit_mask); | |||
| ||||
942 | ||||
943 | // Return | |||
944 | return; | |||
945 | } | |||
946 | ||||
947 | ||||
948 | /***********************************************************************//** | |||
949 | * @brief Set pending Bit | |||
950 | * | |||
951 | * Write the pending Bit into the data. Note that this method assumes that | |||
952 | * the data have already been loaded. | |||
953 | ***************************************************************************/ | |||
954 | void GFitsTableBitCol::set_pending(void) | |||
955 | { | |||
956 | // Continue only if we have a pending Bit | |||
957 | if (m_bit_pending) { | |||
958 | ||||
959 | // Set or unset Bit | |||
960 | if (m_bit_value) { | |||
961 | m_data[m_bit_byte] = m_data[m_bit_byte] | m_bit_mask; | |||
962 | } | |||
963 | else { | |||
964 | m_data[m_bit_byte] = m_data[m_bit_byte] & ~m_bit_mask; | |||
965 | } | |||
966 | ||||
967 | // Signal that no more Bit is pending | |||
968 | m_bit_pending = false; | |||
969 | ||||
970 | } | |||
971 | ||||
972 | // Return | |||
973 | return; | |||
974 | } |