summaryrefslogtreecommitdiffstats
path: root/fitsy/mapincr.C
diff options
context:
space:
mode:
Diffstat (limited to 'fitsy/mapincr.C')
-rw-r--r--fitsy/mapincr.C599
1 files changed, 599 insertions, 0 deletions
diff --git a/fitsy/mapincr.C b/fitsy/mapincr.C
new file mode 100644
index 0000000..8988bb7
--- /dev/null
+++ b/fitsy/mapincr.C
@@ -0,0 +1,599 @@
+// Copyright (C) 1999-2018
+// Smithsonian Astrophysical Observatory, Cambridge, MA, USA
+// For conditions of distribution and use, see copyright notice in "copyright"
+
+#include "mapincr.h"
+
+#ifndef __WIN32
+
+#include <unistd.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include "head.h"
+
+//#define PAGELIMIT 1073741824
+#define PAGELIMIT 536870912
+
+FitsMapIncr::FitsMapIncr()
+{
+ mapdata_ = NULL;
+ mapsize_ = 0;
+ page_ = 0;
+
+ filesize_ = 0;
+ seek_ = 0;
+
+ dseek_ = 0;
+ nseek_ = 0;
+}
+
+FitsMapIncr::~FitsMapIncr()
+{
+ if (mapdata_)
+ munmap((caddr_t)mapdata_, mapsize_);
+}
+
+FitsHead* FitsMapIncr::headRead()
+{
+ // NOTE: the hdu cleans up after the hdu,
+ // here we only clean up after the data segment
+
+ // mmap will return valid if seek_ is at end of file, so check first
+ if (filesize_-seek_<=0)
+ return NULL;
+
+ // read first BLOCK
+ // seek_ needs to be an increment of getpagesize
+ int pagesize = getpagesize();
+ off_t mmseek = (seek_/pagesize)*pagesize;
+ size_t offset = seek_ - mmseek;
+
+ int fd = open(pName_, O_RDONLY);
+ size_t mmsize = offset+FTY_BLOCK;
+ char* mmdata = (char*)mmap(NULL, mmsize, PROT_READ, MAP_SHARED, fd, mmseek);
+ close(fd);
+
+ // are we valid?
+ if ((long)mmdata == -1)
+ return NULL;
+
+ // simple test
+ if (strncmp(mmdata+offset,"SIMPLE ",8) &&
+ strncmp(mmdata+offset,"XTENSION",8)) {
+ munmap((caddr_t)mmdata, mmsize);
+ return NULL;
+ }
+
+ // can we find 'END'?
+ while (mmsize-offset-FTY_BLOCK < filesize_-seek_) {
+ if (findEnd(mmdata+mmsize-FTY_BLOCK))
+ break;
+
+ // add another BLOCK
+ munmap((caddr_t)mmdata, mmsize);
+ fd = open(pName_, O_RDONLY);
+ mmdata = (char*)mmap(NULL, mmsize+FTY_BLOCK, PROT_READ, MAP_SHARED,
+ fd, mmseek);
+ close(fd);
+
+ // are we valid?
+ if ((long)mmdata == -1)
+ return NULL;
+
+ mmsize += FTY_BLOCK;
+ }
+
+ // do we have a header?
+ FitsHead* hd = new FitsHead(mmdata+offset, mmsize-offset,
+ mmdata, mmsize, FitsHead::MMAP);
+ if (!hd || !hd->isValid()) {
+ delete hd;
+ return NULL;
+ }
+
+ seek_ += mmsize-offset;
+
+ // success!
+ return hd;
+}
+
+void FitsMapIncr::dataSkip(size_t bytes)
+{
+ seek_ += bytes;
+}
+
+void FitsMapIncr::dataSkipBlock(size_t blk)
+{
+ seek_ += blk*FTY_BLOCK;
+}
+
+void FitsMapIncr::found()
+{
+ // at this point we mmap the data segment
+
+ // must find a page boundary
+ int pagesize = getpagesize();
+ off_t mmseek = (seek_/pagesize)*pagesize;
+ size_t offset = seek_ - mmseek;
+
+ int fd = open(pName_, O_RDONLY);
+
+ // determine internal page mode
+ if (!head_->isTable() || !head_->isAsciiTable() || head_->isHeap()) {
+ // no internal paging
+ mapsize_ = head_->databytes()+offset;
+ page_ = 0;
+ }
+ else {
+ // if mapsize_ will exceed our inernal page limit, turn on internal paging
+ if (head_->databytes()+offset > PAGELIMIT) {
+ mapsize_ = PAGELIMIT;
+ page_ = 1;
+
+ dseek_ = seek_;
+ nseek_ = seek_-offset;
+ }
+ else {
+ // small enough, no internal paging
+ mapsize_ = head_->databytes()+offset;
+ page_ = 0;
+ }
+ }
+ mapdata_ = (char*)mmap(NULL, mapsize_, PROT_READ, MAP_SHARED, fd, mmseek);
+ close(fd);
+
+ // are we valid? (we'd better be!)
+ if ((long)mapdata_ == -1) {
+ mapsize_ = 0;
+ mapdata_ = NULL;
+ error();
+ return;
+ }
+
+ // seek to next hdu, even if we are internal paging
+ seek_ += head_->databytes();
+ // data starts after any page boundary
+ data_ = mapdata_+offset;
+
+ dataSize_ = mapsize_;
+ dataSkip_ = 0;
+
+ inherit_ = head_->inherit();
+ valid_ = 1;
+}
+
+char* FitsMapIncr::page(char* ptr, size_t row)
+{
+ if (!page_)
+ // no paging, just return
+ return ptr;
+ else {
+ // be sure that at least 'row' bytes are still available
+ if (ptr <= mapdata_+mapsize_-row)
+ // no problem yet
+ return ptr;
+ else {
+ // how far did we get
+ nseek_ += ptr-mapdata_;
+ // unmap the old segment
+ munmap((caddr_t)mapdata_, mapsize_);
+
+ // next mmap segment
+ int pagesize = getpagesize();
+ off_t mmseek = (nseek_/pagesize)*pagesize;
+ size_t offset = nseek_ - mmseek;
+
+ int fd = open(pName_, O_RDONLY);
+
+ // calc next internal page size
+ if (head_->databytes()+offset-(nseek_-dseek_) > PAGELIMIT)
+ mapsize_ = PAGELIMIT;
+ else
+ mapsize_ = head_->databytes()+offset-(nseek_-dseek_);
+
+ mapdata_ =(char*)mmap(NULL, mapsize_, PROT_READ, MAP_SHARED, fd, mmseek);
+ close(fd);
+
+ // are we valid? (we'd better be!)
+ if ((long)mapdata_ == -1) {
+ //*** what to do here?
+ internalError("Fitsy++ mapincr page() error");
+ mapsize_ = 0;
+ mapdata_ = NULL;
+ }
+
+ nseek_ -= offset;
+ return mapdata_+offset;
+ }
+ }
+}
+
+void FitsMapIncr::resetpage()
+{
+ if (page_) {
+ // ok, get a new page
+ munmap((caddr_t)mapdata_, mapsize_);
+
+ // remap original page
+ int pagesize = getpagesize();
+ off_t mmseek = (dseek_/pagesize)*pagesize;
+ size_t offset = dseek_ - mmseek;
+
+ int fd = open(pName_, O_RDONLY);
+
+ if (head_->databytes()+offset > PAGELIMIT)
+ mapsize_ = PAGELIMIT;
+ else
+ mapsize_ = head_->databytes()+offset;
+
+ mapdata_ =(char*)mmap(NULL, mapsize_, PROT_READ, MAP_SHARED, fd, mmseek);
+ close(fd);
+
+ // are we valid? (we'd better be!)
+ if ((long)mapdata_ == -1) {
+ //*** what to do here?
+ internalError("Fitsy++ mapincr resetpage() error");
+ mapsize_ = 0;
+ mapdata_ = NULL;
+ }
+
+ // reset, we may have moved in memory
+ // found the data, save it
+ nseek_ = dseek_-offset;
+ data_ = mapdata_+offset;
+
+ dataSize_ = mapsize_;
+ dataSkip_ = offset;
+ }
+}
+
+void FitsMapIncr::error()
+{
+ if (manageHead_ && head_)
+ delete head_;
+ head_ = NULL;
+
+ if (managePrimary_ && primary_)
+ delete primary_;
+ primary_ = NULL;
+
+ data_ = NULL;
+
+ dataSize_ = 0;
+ dataSkip_ = 0;
+
+ valid_ = 0;
+}
+
+FitsFitsMapIncr::FitsFitsMapIncr(ScanMode mode)
+{
+ if (!valid_)
+ return;
+
+ if (mode == EXACT || pExt_ || pIndex_>-1)
+ processExact();
+ else
+ processRelax();
+}
+
+void FitsFitsMapIncr::processExact()
+{
+ // simple check for fits file
+ if (!(pExt_ || (pIndex_>0))) {
+
+ // we are only looking for a primary image
+ head_ = headRead();
+ if (head_ && head_->isValid()) {
+ found();
+ return;
+ }
+ }
+ else {
+
+ // we are looking for an extension
+ // keep the primary header
+ primary_ = headRead();
+ managePrimary_ = 1;
+ if (!(primary_ && primary_->isValid())) {
+ error();
+ return;
+ }
+ dataSkipBlock(primary_->datablocks());
+
+ if (pExt_) {
+ while (seek_ < filesize_) {
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+ ext_++;
+
+ if (head_->extname()) {
+ char* a = toUpper(head_->extname());
+ char* b = toUpper(pExt_);
+ if (!strncmp(a,b,strlen(b))) {
+ delete [] a;
+ delete [] b;
+ found();
+ return;
+ }
+ delete [] a;
+ delete [] b;
+ }
+ dataSkipBlock(head_->datablocks());
+ delete head_;
+ head_ = NULL;
+ }
+ }
+ else {
+ for (int i=1; i<pIndex_ && seek_<filesize_; i++) {
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+ ext_++;
+
+ dataSkipBlock(head_->datablocks());
+ delete head_;
+ head_ = NULL;
+ }
+
+ head_ = headRead();
+ if (head_ && head_->isValid()) {
+ ext_++;
+ found();
+ return;
+ }
+ }
+ }
+
+ // Must have an error
+ error();
+}
+
+void FitsFitsMapIncr::processRelax()
+{
+ // check to see if there is an image in the primary
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+
+ if (head_ &&
+ head_->isValid() &&
+ head_->naxes() > 0 &&
+ head_->naxis(0) > 0 &&
+ head_->naxis(1) > 0) {
+ found();
+ return;
+ }
+
+ // ok, no image, save primary and lets check extensions
+ primary_ = head_;
+ managePrimary_ = 1;
+ dataSkipBlock(head_->datablocks());
+ head_ = NULL;
+
+ while (seek_ < filesize_) {
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+ ext_++;
+
+ // check for image
+ if (head_->isImage()) {
+ found();
+ return;
+ }
+
+ // else, check for compressed image
+ if (head_->isBinTable() && head_->find("ZIMAGE")) {
+ found();
+ return;
+ }
+
+ // else, check for bin table named STDEVT, EVENTS, RAYEVENT
+ if (head_->isBinTable() && head_->extname()) {
+ char* a = toUpper(head_->extname());
+ if (!strncmp("STDEVT", a, 6) ||
+ !strncmp("EVENTS", a, 6) ||
+ !strncmp("RAYEVENT", a, 8)) {
+ delete [] a;
+ found();
+ return;
+ }
+ else
+ delete [] a;
+ }
+
+ // else, check for bin table with keyword PIXTYPE = 'HEALPIX '
+ if (head_->isBinTable() && head_->find("PIXTYPE") &&
+ (!strncmp(head_->getString("PIXTYPE"),"HEALPIX",4))) {
+ found();
+ return;
+ }
+
+ // else, check for bin table with keyword NSIDE (also HEALPIX)
+ if (head_->isBinTable() && head_->find("NSIDE")) {
+ found();
+ return;
+ }
+
+ dataSkipBlock(head_->datablocks());
+ delete head_;
+ head_ = NULL;
+ }
+
+ // did not find anything, bail out
+ error();
+}
+
+FitsFitsNextMapIncr::FitsFitsNextMapIncr(FitsFile* p)
+{
+ FitsMapIncr* prev = (FitsMapIncr*)p;
+
+ primary_ = prev->primary();
+ managePrimary_ = 0;
+
+ head_ = prev->head();
+ manageHead_ = 0;
+
+ FitsImageHDU* hdu = (FitsImageHDU*)head_->hdu();
+ data_ = (char*)prev->data() + hdu->imgbytes();
+ dataSize_ = 0;
+ dataSkip_ = 0;
+
+ ext_ = prev->ext();
+ inherit_ = prev->inherit();
+ byteswap_ = prev->byteswap();
+ endian_ = prev->endian();
+ valid_ = 1;
+
+ pcoord_ = prev->pcoord();
+ pxvalid_ = prev->pxvalid();
+ pxmin_ = prev->pxmin();
+ pxmax_ = prev->pxmax();
+ pyvalid_ = prev->pyvalid();
+ pymin_ = prev->pymin();
+ pymax_ = prev->pymax();
+ pzvalid_ = prev->pzvalid();
+ pzmin_ = prev->pzmin();
+ pzmax_ = prev->pzmax();
+ pbvalid_ = prev->pbvalid();
+ pblock_ = prev->pblock();
+
+ filesize_ = prev->filesize();
+ seek_ = prev->seek();
+
+ return;
+}
+
+FitsArrMapIncr::FitsArrMapIncr()
+{
+ if (!valid_)
+ return;
+
+ // reset
+ valid_ = 0;
+
+ // check to see if we have a nonzero width, height, and bitpix
+ if (!validParams())
+ return;
+
+ // check to see if dimensions equal mapped space
+ size_t mmsize = ((size_t)pWidth_*pHeight_*pDepth_*abs(pBitpix_)/8) + pSkip_;
+
+ if (mmsize > filesize_)
+ return;
+
+ // skip to start of data
+ int fd = open(pName_, O_RDONLY);
+ char* mmdata = (char*)mmap(NULL, mmsize, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+
+ // are we valid?
+ if ((long)mmdata == -1)
+ return;
+
+ // new header
+ head_ = new FitsHead(pWidth_, pHeight_, pDepth_, pBitpix_,
+ mmdata, mmsize, FitsHead::ALLOC);
+ if (!head_->isValid())
+ return;
+
+ seek_ = mmsize;
+ data_ = mmdata + pSkip_;
+
+ dataSize_ = mapsize_;
+ dataSkip_ = pSkip_;
+
+ // do we byteswap?
+ setByteSwap();
+
+ // made it this far, must be valid
+ valid_ = 1;
+}
+
+FitsMosaicMapIncr::FitsMosaicMapIncr()
+{
+ if (!valid_)
+ return;
+
+ // keep the primary header
+ primary_ = headRead();
+ managePrimary_ = 1;
+ if (!(primary_ && primary_->isValid())) {
+ error();
+ return;
+ }
+ dataSkipBlock(primary_->datablocks());
+
+ // first extension
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+ ext_++;
+ found();
+}
+
+FitsMosaicNextMapIncr::FitsMosaicNextMapIncr(FitsFile* p)
+{
+ FitsMapIncr* prev = (FitsMapIncr*)p;
+
+ pName_ = dupstr(prev->pName());
+ filesize_ = prev->filesize();
+ seek_ = prev->seek();
+
+ primary_ = prev->primary();
+ managePrimary_ = 0;
+ ext_ = prev->ext();
+
+ head_ = headRead();
+ if (!(head_ && head_->isValid())) {
+ error();
+ return;
+ }
+ ext_++;
+ found();
+}
+
+#else
+
+FitsMapIncr::FitsMapIncr()
+{
+ mapdata_ = NULL;
+ mapsize_ = 0;
+}
+
+FitsMapIncr::~FitsMapIncr() {}
+
+FitsHead* FitsMapIncr::headRead() {}
+void FitsMapIncr::dataSkip(size_t bytes) {}
+void FitsMapIncr::dataSkipBlock(size_t blk) {}
+void FitsMapIncr::found() {}
+char* FitsMapIncr::page(char* ptr, size_t row)
+{
+ return NULL;
+}
+void FitsMapIncr::resetpage() {}
+void FitsMapIncr::error() {}
+FitsFitsMapIncr::FitsFitsMapIncr(ScanMode mode) {}
+void FitsFitsMapIncr::processExact() {}
+void FitsFitsMapIncr::processRelax() {}
+
+FitsFitsNextMapIncr::FitsFitsNextMapIncr(FitsFile* p) {}
+FitsArrMapIncr::FitsArrMapIncr() {}
+FitsMosaicMapIncr::FitsMosaicMapIncr() {}
+FitsMosaicNextMapIncr::FitsMosaicNextMapIncr(FitsFile* p) {}
+#endif