Line data Source code
1 : //# VLAArchiveInput.cc: This class reads and reconstructs VLA archive records 2 : //# Copyright (C) 1995,1999,2000,2001,2002 3 : //# Associated Universities, Inc. Washington DC, USA. 4 : //# 5 : //# This library is free software; you can redistribute it and/or modify it 6 : //# under the terms of the GNU Library General Public License as published by 7 : //# the Free Software Foundation; either version 2 of the License, or (at your 8 : //# option) any later version. 9 : //# 10 : //# This library is distributed in the hope that it will be useful, but WITHOUT 11 : //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 : //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public 13 : //# License for more details. 14 : //# 15 : //# You should have received a copy of the GNU Library General Public License 16 : //# along with this library; if not, write to the Free Software Foundation, 17 : //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA. 18 : //# 19 : //# Correspondence concerning AIPS++ should be addressed as follows: 20 : //# Internet email: casa-feedback@nrao.edu. 21 : //# Postal address: AIPS++ Project Office 22 : //# National Radio Astronomy Observatory 23 : //# 520 Edgemont Road 24 : //# Charlottesville, VA 22903-2475 USA 25 : //# 26 : //# $Id$ 27 : 28 : #include <nrao/VLA/VLATapeInput.h> 29 : #include <casacore/casa/Utilities/Assert.h> 30 : #include <casacore/casa/Exceptions/Error.h> 31 : #include <casacore/casa/IO/MemoryIO.h> 32 : 33 : const uInt VLATapeInput::ReadSize = VLAArchiveInput::BlockSize * 34 : VLAArchiveInput::MaxBlocksPerPhysicalRecord; 35 : 36 0 : VLATapeInput::VLATapeInput(const Path& device, uInt whichFile) 37 : :VLAArchiveInput(), 38 0 : itsTape(device), 39 0 : itsFiles(1,whichFile), 40 0 : itsCurFile(-1), 41 0 : itsBuffer(VLATapeInput::ReadSize) 42 : { 43 0 : itsTape.setVariableBlockSize(); 44 0 : if (!nextFile()) { 45 0 : throw(AipsError("VLATapeInput:: problem positioning the tape to file " + 46 0 : String::toString(whichFile))); 47 : } 48 0 : } 49 : 50 0 : VLATapeInput::VLATapeInput(const Path& device, const Block<uInt>& whichFiles) 51 : :VLAArchiveInput(), 52 0 : itsTape(device), 53 0 : itsFiles(whichFiles), 54 0 : itsCurFile(-1), 55 0 : itsBuffer(VLATapeInput::ReadSize) 56 : { 57 0 : itsTape.setVariableBlockSize(); 58 0 : const uInt nFiles = itsFiles.nelements(); 59 0 : if (nFiles == 0) { 60 0 : throw(AipsError("VLATapeInput:: no tape file specified")); 61 : } 62 0 : uInt lastFile = 0; 63 0 : for (uInt i = 0; i < nFiles; i++) { 64 0 : uInt& thisFile = itsFiles[i]; 65 0 : if ((thisFile == 0) && (lastFile != 0)) { 66 0 : thisFile = lastFile + 1; 67 : } 68 0 : if ((thisFile != 0) && (thisFile <= lastFile)) { 69 0 : throw(AipsError 70 0 : ("VLATapeInput:: badly ordered or incorrect file numbers")); 71 : } 72 0 : lastFile = thisFile; 73 : } 74 0 : if (!nextFile()) { 75 0 : throw(AipsError("VLATapeInput:: problem positioning the tape to file " + 76 0 : String::toString(whichFiles[0]))); 77 : } 78 0 : } 79 : 80 0 : VLATapeInput::~VLATapeInput() { 81 0 : } 82 : 83 0 : Bool VLATapeInput::read() { 84 0 : while (nextRecord() == false && nextFile() == true); 85 0 : return hasData(); 86 : } 87 : 88 : // Find an initial record. An initial record MUST have the first 2-byte integer 89 : // as 1 and the next 2-byte integer as a number greater than zero. If we have 90 : // not found an initial record after searching 5MBytes worth of data then just 91 : // give up. 92 0 : Bool VLATapeInput::findFirstRecord(Short& m) { 93 0 : const uInt maxBytesToSearch = 5*1024*1024; 94 0 : Short n = 0 ; 95 0 : m = 0; 96 0 : uInt bytesSearched = 0; 97 : // Search for the correct sequence number or give up after a while. 98 0 : uInt bytesRead = 0; 99 0 : while (!(n == 1 && m > 0) && (bytesSearched <= maxBytesToSearch)) { 100 0 : bytesSearched += bytesRead; 101 0 : bytesRead = VLATapeInput::ReadSize; 102 0 : if (fillBuffer(bytesRead) == false) return false; 103 : // copy just enough bytes into the MemoryIO object to find out what the 104 : // sequence numbers are 105 0 : itsRecord.seek(0); 106 0 : itsRecord.write(VLAArchiveInput::HeaderSize, itsBuffer.storage()); 107 0 : itsRecord.seek(0); 108 0 : itsRecord >> n; 109 0 : itsRecord >> m; 110 : } 111 0 : if (bytesSearched > maxBytesToSearch) { 112 0 : itsMemIO->clear(); 113 0 : return false; 114 : } 115 : // OK so we have found the beginning of the first record. Copy the rest of 116 : // the buffer into the record. 117 : uInt bytesToCopy; 118 0 : if (m != 1) { // Need to copy VLATapeInput::ReadSize bytes 119 0 : bytesToCopy = VLATapeInput::ReadSize - VLAArchiveInput::HeaderSize; 120 : } else {// If m=1 we probably can copy less bytes than the amount of 121 : // data read. To work this out we need to find the logical record size. 122 0 : itsRecord.seek(0); 123 0 : itsRecord.write(4, itsBuffer.storage() + VLAArchiveInput::HeaderSize); 124 0 : itsRecord.seek(0); 125 : Int logicalRecordSize; 126 0 : itsRecord >> logicalRecordSize; 127 0 : bytesToCopy = logicalRecordSize * 2; 128 : } 129 0 : itsRecord.seek(0); 130 0 : itsRecord.write(bytesToCopy, 131 0 : itsBuffer.storage() + VLAArchiveInput::HeaderSize); 132 0 : DebugAssert(n == 1, AipsError); 133 0 : DebugAssert(m > 0, AipsError); 134 0 : return true; 135 : } 136 : 137 0 : Bool VLATapeInput::fillBuffer(uInt& bytesToRead) { 138 : // cerr << " Trying to read " << bytesToRead << " bytes" << endl; 139 0 : DebugAssert(bytesToRead <= VLATapeInput::ReadSize, AipsError); 140 0 : DebugAssert(bytesToRead%VLAArchiveInput::BlockSize == 0, AipsError); 141 0 : const Int bytesRead = itsTape.read(bytesToRead, itsBuffer.storage(), false); 142 : // cerr << " Bytes read: " << bytesRead 143 : // << " Position: " << itsInputPtr->seek(0L, ByteIO::Current) 144 : // << " Length: " << itsInputPtr->length() 145 : // << endl; 146 0 : if ((bytesRead <= 0) || (bytesRead%VLAArchiveInput::BlockSize != 0)) { 147 0 : itsMemIO->clear(); 148 0 : return false; 149 : } 150 0 : bytesToRead = bytesRead; 151 0 : return true; 152 : } 153 : 154 0 : Bool VLATapeInput::nextFile() { 155 0 : if (itsCurFile == static_cast<Int>(itsFiles.nelements()) - 1) return false; 156 : Int skip; 157 0 : if (itsCurFile < 0) { 158 0 : itsCurFile = 0; 159 0 : if (itsFiles[0] > 0) { 160 0 : itsTape.rewind(); 161 0 : skip = itsFiles[0] - 1; 162 : } else { 163 0 : skip = 0; 164 : } 165 : } else { 166 0 : const Int curFile = itsFiles[itsCurFile]; 167 0 : itsCurFile++; 168 0 : const Int nextFile = itsFiles[itsCurFile]; 169 0 : if ((nextFile != 0) && (curFile == 0)) { 170 0 : itsTape.rewind(); 171 0 : skip = nextFile - 1; 172 : } else { 173 0 : skip = nextFile - curFile - 1; 174 : } 175 : } 176 0 : DebugAssert(skip >= 0, AipsError); 177 0 : if (skip > 0) itsTape.skip(skip); 178 0 : return true; 179 : } 180 : 181 0 : Bool VLATapeInput::nextRecord() { 182 : // Clear the internal buffers and reset the flags as we will try to read some 183 : // more data. 184 0 : const Bool gotDataPrev = itsMemIO->length() > 0 ? true : false; 185 0 : itsMemIO->clear(); 186 : // Find an initial record. 187 0 : Short n = 1, m; 188 0 : if (findFirstRecord(m) == false) { 189 0 : if (gotDataPrev) return false; // End of file 190 0 : throw(AipsError("VLATapeInput::nextRecord - Cannot find the start of the " 191 : "record.\nPossible reasons are:\n" 192 : "* your tape is not in VLA archive format\n" 193 : "* you are trying to read the tape label\n" 194 : "* you are trying to read beyond the end of the tape\n" 195 0 : "* you have a corrupted tape.")); 196 : 197 : } 198 0 : uInt thisReadSize = itsMemIO->length(); 199 0 : DebugAssert(thisReadSize >= VLAArchiveInput::HeaderSize, AipsError); 200 : // We have the first physical record in Memory. Now decode how long this 201 : // logical record is. 202 0 : itsRecord.seek(0); 203 : Int logicalRecordSize; 204 0 : itsRecord >> logicalRecordSize; 205 0 : logicalRecordSize *= 2; 206 0 : itsRecord.seek(0, ByteIO::End); 207 0 : Int bytesToRead = logicalRecordSize - thisReadSize; 208 : // cerr << "Still have " << bytesToRead << " bytes to read out of " 209 : // << logicalRecordSize << " bytes in this record." 210 : // << " The buffer contains " << itsMemIO->length() << " bytes" 211 : // << endl; 212 0 : while (bytesToRead > 0) { 213 0 : if (bytesToRead < static_cast<Int>(VLATapeInput::ReadSize)) { 214 0 : thisReadSize = (bytesToRead-1)/VLAArchiveInput::BlockSize + 1; 215 0 : thisReadSize *= VLAArchiveInput::BlockSize; 216 : } else { 217 0 : thisReadSize = VLATapeInput::ReadSize; 218 : } 219 : 220 0 : if (fillBuffer(thisReadSize) == false) return false; 221 : // Check the sequence numbers 222 : { 223 0 : itsRecord.write(VLAArchiveInput::HeaderSize, itsBuffer.storage()); 224 0 : itsRecord.seek(-static_cast<Int64>(VLAArchiveInput::HeaderSize), 225 : ByteIO::End); 226 : Short newn, newm; 227 0 : itsRecord >> newn; 228 0 : itsRecord >> newm; 229 : // cerr << "Sequence numbers: Found m = " << newm << " n = " << newn; 230 : // cerr << " Expected m = " << m << " n = " << n+1 << endl; 231 0 : if (newm != m || ++n != newn) { 232 0 : itsMemIO->clear(); 233 0 : return false; 234 : } 235 0 : itsRecord.seek(-static_cast<Int64>(VLAArchiveInput::HeaderSize), 236 : ByteIO::End); 237 : } 238 : // The sequence numbers are OK so write the rest of the data 239 0 : const uInt bytesToWrite = thisReadSize -4u; 240 : //const uInt bytesToWrite = thisReadSize < static_cast<uInt>(bytesToRead) ? 241 : //(thisReadSize - 4u): thisReadSize; 242 : 243 0 : itsRecord.write(bytesToWrite, 244 0 : itsBuffer.storage() + VLAArchiveInput::HeaderSize); 245 0 : bytesToRead -= thisReadSize; 246 : // cerr << "Read a logical block. Still have " 247 : // << bytesToRead << " bytes to read. The buffer contains " 248 : // << itsMemIO->length() << " bytes" << endl; 249 : } 250 0 : itsRecord.seek(0); 251 0 : return true; 252 : } 253 : // Local Variables: 254 : // compile-command: "gmake VLATapeInput; cd test; gmake OPTLIB=1 tVLATapeInput" 255 : // End: