casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
VLATapeInput.h
Go to the documentation of this file.
00001 //# VLATapeInput.h: This class reads VLA archive records from a Tape 
00002 //# Copyright (C) 1995,1999,2000,2001
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id$
00027 
00028 #ifndef NRAO_VLATAPEINPUT_H
00029 #define NRAO_VLATAPEINPUT_H
00030 
00031 #include <casa/aips.h>
00032 #include <casa/IO/TapeIO.h>
00033 #include <casa/Containers/Block.h>
00034 #include <nrao/VLA/VLAArchiveInput.h>
00035 
00036 #include <casa/namespace.h>
00037 namespace casa { //# NAMESPACE CASA - BEGIN
00038 class Path;
00039 class ByteSource;
00040 } //# NAMESPACE CASA - END
00041 
00042 
00043 // <summary>This class reads VLA archive records from a Tape</summary>
00044 
00045 // <reviewed reviewer="" date="" tests="" demos="">
00046 
00047 // <prerequisite>
00048 // <ol>
00049 //   <li> The IO Module
00050 // </ol>
00051 // </prerequisite>
00052 //
00053 // <etymology>
00054 // This class is designed to reads VLA archive records from a Tape
00055 // </etymology>
00056 //
00057 // <synopsis> 
00058 
00059 // This class is designed to read VLA archive data.  The data may be read from
00060 // a disk, tape drive or any other data source supported by the IO module.  A
00061 // call to the operator++() function assembles the next reconstructed VLA
00062 // archive data record from the input. A reference to this data can be
00063 // obtained using the logicalRecord function.
00064 //
00065 // Refer to the "VLA Archive Data Format", VLA Computer Memorandum 186
00066 // by G.C. Hunt, K.P. Sowinski, and T.J. Bottomly; June 1993.
00067 // (This is also available as AIPS++ note 159)
00068 //
00069 // The VLA archive records are always a multiple of 2048 bytes.  The
00070 // record sizes were designed for use with magnetic tapes, so there is
00071 // a maximum physical record size of 13*2048=26624 bytes.
00072 //
00073 // The low level class (blockio), that actually does the I/O, allows
00074 // for a record (hereinafter chunk) size and for a input block size of
00075 // a multiple of the chunk size.  The low level read operation tests
00076 // for the number of bytes actually read from the device.
00077 //
00078 // The helper classes VlaDiskInput, VlaTapeInput, and VlaStdInput are
00079 // designed to deal with the low level input from the devices in an
00080 // analogous fashion to the ones used for FITS input.
00081 //
00082 // Since a read may be issued for an arbitrary number of bytes from a
00083 // disk, the chunk multiple is arbitrary and may be used to tune the
00084 // speed of operation.  There is an obvious trade-off between the
00085 // block size created in the blockio class and the number of read
00086 // operations.
00087 //
00088 // The story is quite different for tape input.  A read request for at
00089 // least the maximum physical record size must be made to avoid loss of
00090 // data.  Since a single tape record will be read with a single read
00091 // operation, there is no point is having it any larger.  The chunk
00092 // multiple must be exactly 13 so that the block size is 26624.
00093 //
00094 // The reconstitution algorithm is as follows:
00095 //
00096 // 1. Read a 2048 chunk from the input.
00097 //
00098 // The first two 16-bit integers should contain the values 1 and n,
00099 // where n is the number of "physical records" in the current "logical  
00100 // record."  (If the first value is not 1, then the chunk is rejected
00101 // and a new one read until the first 16-bit value is 1.)  These two
00102 // values are not part of the reconstituted "logical record."
00103 //
00104 // 2. The next 32-bit integer contains the length of the "logical
00105 // record" in 16-bit words.  The buffer is resized so that it can
00106 // contain the whole reconstituted "logical record."
00107 //
00108 // 3. The remainder of the chunk is copied to the buffer.
00109 //
00110 // 4. Successive chunks are read from the input.
00111 //
00112 // The chunks are copied into the buffer until the "logical record"
00113 // is complete.  For "logical records" longer than 26620 byte, this is
00114 // not the whole story.  Each "physical record" contains maximum of 13
00115 // chunks.  When the first "physical record" of 13 chunks has been read,
00116 // the next chunk will be the first of the next "physical record."  The
00117 // first two 16-bit integers will now be 2 and n, to indicate that this
00118 // is the second "physical record" of the sequence.  These 4 bytes are
00119 // decoded and the rest of this chunk is copied to the buffer.  And so
00120 // on...
00121 //
00122 // An end-of-file condition on the input will cause record processing
00123 // to be declared complete.  
00124 // </synopsis> 
00125 //
00126 // <example>
00127 // To open and read a VLA archive data file
00128 // <code>
00129 //    VLAArchiveInput *in;
00130 //    Block <Char> *buff;
00131 //    String fileName = " ";
00132 //    String fileType = "tape";
00133 //
00134 //    if (fileType == String("tape")) {
00135 //        in = new VLAArchiveInput(fileName.chars(), VLAArchiveInput::Tape);
00136 //    } else {
00137 //        in = new VLAArchiveInput(fileName.chars(), VLAArchiveInput::Disk);
00138 //    }
00139 //
00140 //    uInt record = 0;
00141 //    for (buff=&(in->next()); in->atEnd()==False; buff=&(in->next()), record++) {
00142 //        cout << "Record" << record << endl;
00143 //        // process record pointed to by buff
00144 //    }
00145 // </code>
00146 //
00147 // </example>
00148 //
00149 // <motivation>
00150 // </motivation>
00151 //
00152 // <todo asof="">
00153 // <ol>
00154 //   <li> Bulletproofing - check for realistic buffer size (<1e6)
00155 //   <li> Bulletproofing - check newn and newm on each read
00156 //   <li> What happens after a single end-of-file on a tape drive?
00157 //   <li> Add record skipping
00158 //   <li> Should it work with stdin?  This is in place but not debugged.
00159 // </ol>
00160 // </todo>
00161 
00162 class VLATapeInput: public VLAArchiveInput
00163 {
00164 public: 
00165   // Create an object that reads its data from the specified file on the
00166   // specified tape device. The whichFile argument indicates which tape to read
00167   // from the tape with zero meaning "read the next file". The first file
00168   // containing data (ie ignoring the tape header file) is file 1. An exception
00169   // is thrown if there is any problem opening (readonly) the tape device or if
00170   // the tape cannot be positioned to the start of the specified file.
00171   VLATapeInput(const Path& device, uInt whichFile=0);
00172     
00173   // Create an object that reads its data from the specified files on the
00174   // specified tape device. The tape is rewound and only the specified file is
00175   // read. The first file containing data (ie ignoring the tape header file) is
00176   // file 1 and zero means "read the next file". An exception is thrown if
00177   // there is any problem opening (readonly) the tape device or if the tape
00178   // cannot be positioned to the start of the first specified file. The file
00179   // numbers should be in increasing order as only one pass through the tape is
00180   // made.
00181   VLATapeInput(const Path& device, const Block<uInt>& whichFiles);
00182     
00183   // The destructor closes the tape device.
00184   ~VLATapeInput();
00185 
00186   // Reads the next logical record from specified tape. Returns False if
00187   // there was a problem assembling the next record ie., it returns the value
00188   // of the hasData() member function.
00189   virtual Bool read();
00190 
00191 private: 
00192   //# This is the amount data that is read with every system call. It needs to
00193   //# be at least as big as the biggest record on tape. However it can bigger
00194   //# as this code will not complain if less data was read (although all data
00195   //# read must be in multiples of the BlockSize)
00196   static const uInt ReadSize;
00197 
00198   //# The default constructor is private and undefined
00199   VLATapeInput();
00200     
00201   //# The copy constructor is private and undefined
00202   VLATapeInput(const VLATapeInput& other);
00203 
00204   //# The assignment operator is private and undefined
00205   VLATapeInput& operator=(const VLATapeInput& other);
00206 
00207   //# Reads through a VLA archive looking for the first physical record in a
00208   //# logical record. Returns False if the first record could not be found. If
00209   //# It was found then this function also returns the number of physical
00210   //# records in this logical record.
00211   Bool findFirstRecord(Short& m);
00212 
00213   //# Positions the tape to the beginning of the next file. Uses and
00214   //# manipulates the itsFiles and itsCurFile data members. Returns False if
00215   //# the tape could not be positioned.
00216   Bool nextFile();
00217 
00218   //# Reads the next record from the tape. Skips over bad data but not
00219   //# filemarks.  Throws an exception if no valid records could be read.
00220   Bool nextRecord();
00221 
00222   //# Read the specified number of bytes from the current ByteIO. Returns False
00223   //# if no data was written, a read error was detected or the data read was
00224   //# not a multiple of the BlockSize.  Sets the appropriate Flags when
00225   //# returning False. Writes the data into an internal buffer.
00226   Bool fillBuffer(uInt& bytesToRead);
00227 
00228   //# This object that provides the data input. Usually a Tape, File, Socket
00229   //# etc.
00230   TapeIO itsTape;
00231 
00232   //# This object indicates which files we are to read on the tape;
00233   Block<uInt> itsFiles;
00234 
00235   //# An index into the itsFiles block indicating which file, in tape, we
00236   //# are currently reading. A negative number indicates that the tape has not
00237   //# been positioned yet.
00238   Int itsCurFile;
00239 
00240   //# A temporary buffer that is used to store the data prior to copying it
00241   //# into the MemoryIO object. This is necessary because the MemoryIO object
00242   //# does not allow you low level access to its data.
00243   Block<uChar> itsBuffer;
00244 };
00245 #endif