All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nom.tam.fits.Data Maven / Gradle / Ivy

package nom.tam.fits;

import java.io.EOFException;

/*
 * #%L
 * nom.tam FITS library
 * %%
 * Copyright (C) 2004 - 2024 nom-tam-fits
 * %%
 * This is free and unencumbered software released into the public domain.
 *
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 *
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * #L%
 */

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

import nom.tam.fits.utilities.FitsCheckSum;
import nom.tam.util.ArrayDataInput;
import nom.tam.util.ArrayDataOutput;
import nom.tam.util.FitsInputStream;
import nom.tam.util.RandomAccess;

import static nom.tam.util.LoggerHelper.getLogger;

/**
 * The data segment of an HDU.
 * 

* This is the object which contains the actual data for the HDU. *

*
    *
  • For images and primary data this is a simple (but possibly multi-dimensional) primitive array. When group data is * supported it will be a possibly multidimensional array of group objects. *
  • For ASCII data it is a two dimensional Object array where each of the constituent objects is a primitive array of * length 1. *
  • For Binary data it is a two dimensional Object array where each of the constituent objects is a primitive array * of arbitrary (more or less) dimensionality. *
*/ @SuppressWarnings("deprecation") public abstract class Data implements FitsElement { private static final Logger LOG = getLogger(Data.class); private static final int FITS_BLOCK_SIZE_MINUS_ONE = FitsFactory.FITS_BLOCK_SIZE - 1; /** * @deprecated Will be private. Access via {@link #getFileOffset()} The starting location of the data when last read */ @Deprecated protected long fileOffset = -1; /** * @deprecated Will be removed. Use {@link #getTrueSize()} instead. The size of the data when last read */ @Deprecated protected long dataSize; /** * @deprecated Will be private. Use {@link #getRandomAccessInput()} instead. The input stream used. */ @Deprecated protected RandomAccess input; /** The data checksum calculated from the input stream */ private long streamSum = 0L; /** * Returns the random accessible input from which this data can be read, if any. * * @return the random access input from which we can read the data when needed, or null if this data * object is not associated to an input, or it is not random accessible. */ protected final RandomAccess getRandomAccessInput() { return input; } /** * Describe the structure of this data object in the supplied header. * * @param head header to fill with the data from the current data object * * @throws FitsException if the operation fails */ protected abstract void fillHeader(Header head) throws FitsException; /** * Checks if the data should be assumed to be in deferred read mode. * * @return true if it is set for deferred reading at a later time, or else false if this * data is currently loaded into RAM. #see {@link #detach()} * * @since 1.17 */ @SuppressWarnings("resource") public boolean isDeferred() { return getTrueSize() != 0 && isEmpty() && getRandomAccessInput() != null; } /** * Checks if the data content is currently empty, i.e. no actual data is currently stored in memory. * * @return true if there is no actual data in memory, otherwise false * * @see #isDeferred() * @see #getCurrentData() * * @since 1.18 */ public boolean isEmpty() { return getCurrentData() == null; } /** * Computes and returns the FITS checksum for this data, for example to compare against the stored * DATASUM in the FITS header (e.g. via {@link BasicHDU#getStoredDatasum()}). This method always * computes the checksum from data in memory. As such it will fully load deferred read mode data into RAM to perform * the calculation, and use the standard padding to complete the FITS block for the calculation. As such the * checksum may differ from that of the file if the file uses a non-standard padding. Hence, for verifying data * integrity as stored in a file {@link BasicHDU#verifyDataIntegrity()} or {@link BasicHDU#verifyIntegrity()} should * be preferred. * * @return the computed FITS checksum from the data (fully loaded in memory). * * @throws FitsException if there was an error while calculating the checksum * * @see BasicHDU#getStoredDatasum() * @see BasicHDU#verifyDataIntegrity() * @see BasicHDU#verifyIntegrity() * * @since 1.17 */ public long calcChecksum() throws FitsException { return FitsCheckSum.checksum(this); } /** * Returns the checksum value calculated duting reading from a stream. It always returns a value that is greater or * equal to zero. It is only populated when reading from {@link FitsInputStream} imputs, and never from other types * of inputs. The default return value is zero. * * @return the checksum calculated for the data read from a stream, or else zero if the data was not read from the * stream. * * @see FitsInputStream * @see Header#getStreamChecksum() * * @since 1.18.1 */ final long getStreamChecksum() { return streamSum; } /** * Returns the underlying Java representation of the data contained in this HDU's data segment. Typically it will * return a Java array of some kind. * * @return the underlying Java representation of the data core object, such as a multi-dimensional * Java array. * * @throws FitsException if the data could not be gathered. * * @see #isDeferred() * @see #ensureData() */ public Object getData() throws FitsException { ensureData(); return getCurrentData(); } /** * Returns the data content that is currently in memory. In case of a data object in deferred read state (that is * its prescription has been parsed from the header, but no data content was loaded yet from a random accessible * input), this call may return null or an object representing empty data. * * @return The current data content in memory. * * @see #getData() * @see #ensureData() * @see #isDeferred() * @see #isEmpty() * * @since 1.18 */ protected abstract Object getCurrentData(); @Override public long getFileOffset() { return fileOffset; } /** * Same as {@link #getData()}. * * @return The data content as represented by a Java object.. * * @throws FitsException if the data could not be gathered . */ public final Object getKernel() throws FitsException { return getData(); } @Override public long getSize() { return FitsUtil.addPadding(getTrueSize()); } /** * Returns the calculated byte size of the data, regardless of whether the data is currently in memory or not. * * @return the calculated byte size for the data. */ protected abstract long getTrueSize(); /** *

* Load data from the current position of the input into memory. This may be triggered immediately when calling * {@link #read(ArrayDataInput)} if called on a non random accessible input, or else later when data is accessed via * {@link #ensureData()}, for example as a result of a {@link #getData()} call. This method will not be called * unless there is actual data of non-zero size to be read. *

*

* Implementations should create appropriate data structures and populate them from the specified input. *

* * @param in The input from which to load data * * @throws IOException if the data could not be loaded from the input. * @throws FitsException if the data is garbled. * * @see #read(ArrayDataInput) * @see #ensureData() * @see #getData() * @see #isDeferred() * * @since 1.18 */ protected abstract void loadData(ArrayDataInput in) throws IOException, FitsException; private void skipPadding(ArrayDataInput in) throws PaddingException, FitsException { try { in.skipAllBytes((long) FitsUtil.padding(getTrueSize())); } catch (EOFException e) { throw new PaddingException("EOF while skipping padding after data segment", e); } catch (IOException e) { throw new FitsException("IO error while skipping padding after data segment", e); } } /** * Makes sure that data that may have been deferred earlier from a random access input is now loaded into memory. * * @throws FitsException if the deferred data could not be loaded. * * @see #getData() * @see #read(ArrayDataInput) * @see #isDeferred() * * @since 1.18 */ protected void ensureData() throws FitsException { if (!isDeferred()) { return; } try { long pos = input.getFilePointer(); input.seek(getFileOffset()); loadData(input); input.seek(pos); } catch (IOException e) { throw new FitsException("error reading deferred data: " + e, e); } } /** *

* Reads the data or skips over it for reading later, depending on whether reading from a stream or a random * acessible input, respectively. *

*

* In case the argument is a an instance of {@link RandomAccess} input (such as a {@link nom.tam.util.FitsFile}, the * call will simply note where in the file the data segment can be found for reading at a later point, only when the * data content is accessed. This 'deferred' reading behavior make it possible to process large HDUs even with small * amount of RAM, and can result in a significant performance boost when inspectring large FITS files, or using only * select content from large FITS files. *

* * @throws PaddingException if there is missing padding between the end of the data segment and the enf-of-file. * @throws FitsException if the data appears to be corrupted. * * @see #getData() * @see #ensureData() */ @Override public void read(ArrayDataInput in) throws PaddingException, FitsException { detach(); if (in == null) { return; } if (in instanceof FitsInputStream) { ((FitsInputStream) in).nextChecksum(); } streamSum = 0L; setFileOffset(in); if (getTrueSize() == 0) { return; } if (in instanceof RandomAccess) { // If random accessible, then defer reading.... try { in.skipAllBytes(getTrueSize()); } catch (IOException e) { throw new FitsException("Unable to skip over data segment:" + e, e); } } else { try { loadData(in); } catch (IOException e) { throw new FitsException("error reading data: " + e, e); } } skipPadding(in); if (in instanceof FitsInputStream) { streamSum = ((FitsInputStream) in).nextChecksum(); } } @SuppressWarnings("resource") @Override public boolean reset() { try { FitsUtil.reposition(getRandomAccessInput(), getFileOffset()); return true; } catch (Exception e) { LOG.log(Level.SEVERE, "Unable to reset", e); return false; } } @SuppressWarnings("resource") @Override public void rewrite() throws FitsException { if (isDeferred()) { return; // Nothing to do... } if (!rewriteable()) { throw new FitsException("Illegal attempt to rewrite data"); } FitsUtil.reposition(getRandomAccessInput(), getFileOffset()); write((ArrayDataOutput) getRandomAccessInput()); try { ((ArrayDataOutput) getRandomAccessInput()).flush(); } catch (IOException e) { throw new FitsException("Error in rewrite flush: ", e); } } @Override public boolean rewriteable() { return input != null && getFileOffset() >= 0 && (getTrueSize() + FITS_BLOCK_SIZE_MINUS_ONE) / FitsFactory.FITS_BLOCK_SIZE == (getTrueSize() + FITS_BLOCK_SIZE_MINUS_ONE) / FitsFactory.FITS_BLOCK_SIZE; } /** * Detaches this data object from the input (if any), such as a file or stream, but not before loading data from the * previously assigned input into memory. * * @throws FitsException if there was an issue loading the data from the previous input (if any) * * @see #isDeferred() * * @since 1.18 */ public void detach() throws FitsException { ensureData(); clearInput(); } private void clearInput() { input = null; fileOffset = -1; dataSize = 0L; } /** * Record the information necessary for eading the data content at a later time (deferred reading). * * @param o reread information. * * @see #isDeferred() */ protected void setFileOffset(ArrayDataInput o) { if (o instanceof RandomAccess) { fileOffset = FitsUtil.findOffset(o); dataSize = getTrueSize(); input = (RandomAccess) o; } else { clearInput(); } } @Override public abstract void write(ArrayDataOutput o) throws FitsException; /** * Returns an approprotae HDU object that encapsulates this FITS data, and contains the minimal mandatory header * description for that data. * * @throws FitsException If the data cannot be converted to an HDU for some reason. * * @return a HDU object ocntaining the data and its minimal required header description */ public abstract BasicHDU toHDU() throws FitsException; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy