USGS

Isis 3.0 Object Programmers' Reference

Home

Cube.cpp
Go to the documentation of this file.
1 
23 #include "IsisDebug.h"
24 #include "Cube.h"
25 
26 #include <sstream>
27 #include <unistd.h>
28 
29 #include <QDebug>
30 #include <QFile>
31 #include <QFileInfo>
32 #include <QMutex>
33 
34 #include "Application.h"
35 #include "Camera.h"
36 #include "CameraFactory.h"
37 #include "CubeAttribute.h"
38 #include "CubeBsqHandler.h"
39 #include "CubeTileHandler.h"
40 #include "Endian.h"
41 #include "FileName.h"
42 #include "Histogram.h"
43 #include "IException.h"
44 #include "LineManager.h"
45 #include "Message.h"
46 #include "Preference.h"
47 #include "ProgramLauncher.h"
48 #include "Projection.h"
49 #include "SpecialPixel.h"
50 #include "Statistics.h"
51 
52 using namespace std;
53 
54 namespace Isis {
56  Cube::Cube() {
57  construct();
58  }
59 
68  Cube::Cube(const FileName &fileName, QString access) {
69  construct();
70  open(fileName.toString(), access);
71  }
72 
73 
75  Cube::~Cube() {
76  close();
77 
78  delete m_mutex;
79  m_mutex = NULL;
80 
81  delete m_camera;
82  m_camera = NULL;
83 
84  delete m_projection;
85  m_projection = NULL;
86 
87  delete m_formatTemplateFile;
88  m_formatTemplateFile = NULL;
89  }
90 
91 
97  bool Cube::isOpen() const {
98  bool open = (m_ioHandler != NULL);
99 
100  ASSERT(open == (bool)m_labelFile);
101  ASSERT(open == (bool)m_labelFileName);
102  ASSERT(open == (bool)m_label);
103 
104  return open;
105  }
106 
107 
116  bool Cube::isProjected() const {
117  return label()->findObject("IsisCube").hasGroup("Mapping");
118  }
119 
120 
127  bool Cube::isReadOnly() const {
128  bool readOnly = false;
129 
130  if (!isOpen()) {
131  QString msg = "No cube opened";
132  throw IException(IException::Programmer, msg, _FILEINFO_);
133  }
134 
135  if ((m_labelFile->openMode() & QIODevice::ReadWrite) != QIODevice::ReadWrite)
136  readOnly = true;
137 
138  return readOnly;
139  }
140 
141 
149  bool Cube::isReadWrite() const {
150  return !isReadOnly();
151  }
152 
153 
162  bool Cube::labelsAttached() const {
163  return m_attached;
164  }
165 
166 
174  void Cube::close(bool removeIt) {
175  if (isOpen() && isReadWrite())
176  writeLabels();
177 
178  cleanUp(removeIt);
179  }
180 
181 
182  Cube *Cube::copy(FileName newFile, const CubeAttributeOutput &newFileAttributes) {
183  if (!isOpen()) {
184  throw IException(IException::Unknown,
185  QObject::tr("Cube::copy requires the originating cube to be open"),
186  _FILEINFO_);
187  }
188 
189 
190  Cube *result = new Cube;
191 
192  if (newFileAttributes.labelAttachment() != ExternalLabel) {
193  result->setDimensions(sampleCount(), lineCount(), bandCount());
194  result->setByteOrder(newFileAttributes.byteOrder());
195  result->setFormat(newFileAttributes.fileFormat());
196 
197  if (newFileAttributes.labelAttachment() == DetachedLabel) {
198  result->setLabelsAttached(false);
199  }
200 
201  if (newFileAttributes.propagatePixelType()) {
202  result->setPixelType(pixelType());
203  }
204  else {
205  result->setPixelType(newFileAttributes.pixelType());
206  }
207 
208  if (newFileAttributes.propagateMinimumMaximum()) {
209  if(result->pixelType() == Isis::Real) {
210  result->setBaseMultiplier(0.0, 1.0);
211  }
212  else if(result->pixelType() >= pixelType()) {
213  result->setBaseMultiplier(base(), multiplier());
214  }
215  else {
216  QString msg =
217  QObject::tr("Cannot reduce the output PixelType for [%1] from [%2] without output "
218  "pixel range").arg(newFile.original()).arg(fileName());
219  throw IException(IException::User, msg, _FILEINFO_);
220  }
221  }
222  else {
223  // Not propagating so either the user entered or the programmer did
224  result->setMinMax(newFileAttributes.minimum(), newFileAttributes.maximum());
225  }
226 
227  result->setLabelSize(labelSize(true) + (1024 * 6));
228  }
229  else {
230  if (isReadWrite()) {
231  writeLabels();
232  m_ioHandler->clearCache(true);
233  }
234 
235  result->setExternalDnData(fileName());
236  }
237 
238  // Allocate the cube
239  result->create(newFile.expanded());
240 
241  PvlObject &isisCube = label()->findObject("IsisCube");
242  PvlObject &outIsisCube = result->label()->findObject("IsisCube");
243  for(int i = 0; i < isisCube.groups(); i++) {
244  outIsisCube.addGroup(isisCube.group(i));
245  }
246 
247  if (label()->hasObject("NaifKeywords")) {
248  result->label()->addObject(
249  label()->findObject("NaifKeywords"));
250  }
251 
252  for (int i = 0; i < m_label->objects(); i++) {
253  PvlObject &obj = m_label->object(i);
254  if (obj.isNamed("Table") || obj.isNamed("Polygon") || obj.isNamed("OriginalLabel") ||
255  obj.isNamed("History")) {
256  Isis::Blob t((QString)obj["Name"], obj.name());
257  read(t);
258  result->write(t);
259  }
260  }
261 
262  if (newFileAttributes.labelAttachment() != ExternalLabel) {
263  BufferManager input(sampleCount(), lineCount(), bandCount(),
264  sampleCount(), 1, 1,
265  pixelType());
266  BufferManager output(sampleCount(), lineCount(), bandCount(),
267  sampleCount(), 1, 1,
268  result->pixelType());
269 
270  input.begin();
271  output.begin();
272 
273  while (!input.end()) {
274  read(input);
275  output.Copy(input, false);
276 
277  result->write(output);
278 
279  input.next();
280  output.next();
281  }
282  }
283 
284 // Just in case the orig label doesn't work... here's original code:
285 // if((p_propagateOriginalLabel) && (InputCubes.size() > 0)) {
286 // Isis::Pvl &inlab = *InputCubes[0]->label();
287 // for(int i = 0; i < inlab.objects(); i++) {
288 // if(inlab.Object(i).isNamed("OriginalLabel")) {
289 // Isis::OriginalLabel ol;
290 // InputCubes[0]->read(ol);
291 // cube->write(ol);
292 // }
293 // }
294 // }
295 
296  return result;
297  }
298 
299 
320  void Cube::create(const QString &cubeFileName) {
321  // Already opened?
322  if (isOpen()) {
323  string msg = "You already have a cube opened";
324  throw IException(IException::Programmer, msg, _FILEINFO_);
325  }
326 
327  if (m_samples < 1 || m_lines < 1 || m_bands < 1) {
328  QString msg = "Number of samples [" + toString(m_samples) +
329  "], lines [" + toString(m_lines) + "], or bands [" + toString(m_bands) +
330  "] cannot be less than 1";
331  throw IException(IException::Programmer, msg, _FILEINFO_);
332  }
333 
334  if (m_pixelType == None) {
335  throw IException(IException::Unknown,
336  QString("Cannot create the cube [%1] with a pixel type set to None")
337  .arg(cubeFileName),
338  _FILEINFO_);
339  }
340 
341  if (m_storesDnData) {
342  // Make sure the cube is not going to exceed the maximum size preference
343  BigInt size = (BigInt)m_samples * m_lines *
344  (BigInt)m_bands * (BigInt)SizeOf(m_pixelType);
345 
346  size = size / 1024; // kb
347  size = size / 1024; // mb
348  size = size / 1024; // gb
349 
350  int maxSizePreference = 0;
351 
352  maxSizePreference =
353  Preference::Preferences().findGroup("CubeCustomization")["MaximumSize"];
354 
355  if (size > maxSizePreference) {
356  QString msg;
357  msg += "The cube you are attempting to create [" + cubeFileName + "] is ["
358  + toString(size) + "GB]. This is larger than the current allowed "
359  "size of [" + toString(maxSizePreference) + "GB]. The cube "
360  "dimensions were (S,L,B) [" + toString(m_samples) + ", " +
361  toString(m_lines) + ", " + toString(m_bands) + "] with [" +
362  toString(SizeOf(m_pixelType)) + "] bytes per pixel. If you still "
363  "wish to create this cube, the maximum value can be changed in the"
364  " file [~/.Isis/IsisPreferences] within the group "
365  "CubeCustomization, keyword MaximumSize.";
366  throw IException(IException::User, msg, _FILEINFO_);
367  }
368  }
369 
370  // Expand output name
371  FileName cubFile(cubeFileName);
372  PvlObject isiscube("IsisCube");
373  PvlObject core("Core");
374 
375  if (m_storesDnData) {
376  cubFile = cubFile.addExtension("cub");
377 
378  // See if we have attached or detached labels
379  if (m_attached) {
380  // StartByte is 1-based (why!!) so we need to do + 1
381  core += PvlKeyword("StartByte", toString(m_labelBytes + 1));
382  m_labelFileName = new FileName(cubFile);
383  m_dataFileName = new FileName(cubFile);
384  m_labelFile = new QFile(m_labelFileName->expanded());
385  }
386  else {
387  core += PvlKeyword("StartByte", toString(1));
388  core += PvlKeyword("^Core", cubFile.name());
389  m_dataFileName = new FileName(cubFile);
390  m_dataFile = new QFile(realDataFileName().expanded());
391 
392  FileName labelFileName(cubFile);
393  labelFileName = labelFileName.setExtension("lbl");
394  m_labelFileName = new FileName(labelFileName);
395  m_labelFile = new QFile(m_labelFileName->expanded());
396  }
397 
398  // Create the size of the core
399  PvlGroup dims("Dimensions");
400  dims += PvlKeyword("Samples", toString(m_samples));
401  dims += PvlKeyword("Lines", toString(m_lines));
402  dims += PvlKeyword("Bands", toString(m_bands));
403  core.addGroup(dims);
404 
405  // Create the pixel type
406  PvlGroup ptype("Pixels");
407  ptype += PvlKeyword("Type", PixelTypeName(m_pixelType));
408 
409  // And the byte ordering
410  ptype += PvlKeyword("ByteOrder", ByteOrderName(m_byteOrder));
411  ptype += PvlKeyword("Base", toString(m_base));
412  ptype += PvlKeyword("Multiplier", toString(m_multiplier));
413  core.addGroup(ptype);
414  }
415  else {
416  cubFile = cubFile.addExtension("ecub");
417 
418  ASSERT(m_dataFileName);
419 
420  core += PvlKeyword("^DnFile", m_dataFileName->original());
421 // m_dataFileName = new FileName(cubFile);
422  m_dataFile = new QFile(realDataFileName().expanded());
423 
424  m_labelFileName = new FileName(cubFile);
425  m_labelFile = new QFile(cubFile.expanded());
426  }
427 
428  isiscube.addObject(core);
429 
430  m_label = new Pvl;
431  m_label->addObject(isiscube);
432 
433  // Setup storage reserved for the label
434  PvlObject lbl("Label");
435  lbl += PvlKeyword("Bytes", toString(m_labelBytes));
436  m_label->addObject(lbl);
437 
438  const PvlGroup &pref =
439  Preference::Preferences().findGroup("CubeCustomization");
440  bool overwrite = pref["Overwrite"][0].toUpper() == "ALLOW";
441  if (!overwrite && m_labelFile->exists() && m_labelFile->size()) {
442  QString msg = "Cube file [" + m_labelFileName->original() + "] exists, " +
443  "user preference does not allow overwrite";
444  throw IException(IException::User, msg, _FILEINFO_);
445  }
446 
447  if (!m_labelFile->open(QIODevice::Truncate | QIODevice::ReadWrite)) {
448  QString msg = "Failed to create [" + m_labelFile->fileName() + "]";
449  cleanUp(false);
450  throw IException(IException::Io, msg, _FILEINFO_);
451  }
452 
453  if (m_dataFile) {
454  if (m_storesDnData && !m_dataFile->open(QIODevice::Truncate | QIODevice::ReadWrite)) {
455  QString msg = "Failed to create [" + m_dataFile->fileName() + "]";
456  cleanUp(false);
457  throw IException(IException::Io, msg, _FILEINFO_);
458  }
459  else if (!m_storesDnData && !m_dataFile->open(QIODevice::ReadOnly)) {
460  QString msg = "Failed to open [" + m_dataFile->fileName() + "] for reading";
461  cleanUp(false);
462  throw IException(IException::Io, msg, _FILEINFO_);
463  }
464  }
465 
466  bool dataAlreadyOnDisk = m_storesDnData ? false : true;
467 
468  if (m_format == Bsq) {
469  m_ioHandler = new CubeBsqHandler(dataFile(), m_virtualBandList, realDataFileLabel(),
470  dataAlreadyOnDisk);
471  }
472  else {
473  m_ioHandler = new CubeTileHandler(dataFile(), m_virtualBandList, realDataFileLabel(),
474  dataAlreadyOnDisk);
475  }
476 
477  if (m_storesDnData)
478  m_ioHandler->updateLabels(*m_label);
479 
480  // Write the labels
481  writeLabels();
482  }
483 
484 
485  void Cube::create(
486  const QString &cubeFileName, const CubeAttributeOutput &att) {
487 
488  setByteOrder(att.byteOrder());
489  setFormat(att.fileFormat());
490  setLabelsAttached(att.labelAttachment() == AttachedLabel);
491  if (!att.propagatePixelType())
492  setPixelType(att.pixelType());
493  setMinMax(att.minimum(), att.maximum());
494 
495  // Allocate the cube
496  create(cubeFileName);
497  }
498 
499 
508  void Cube::open(const QString &cubeFileName, QString access) {
509  // Already opened?
510 
511  if (isOpen()) {
512  string msg = "You already have a cube opened";
513  throw IException(IException::Programmer, msg, _FILEINFO_);
514  }
515 
516  initLabelFromFile(cubeFileName, (access == "rw"));
517 
518  // Figure out the name of the data file
519  try {
520  PvlObject &core = m_label->findObject("IsisCube").findObject("Core");
521  if (core.hasKeyword("^Core")) {
522  FileName temp(core["^Core"][0]);
523 
524  if (!temp.originalPath().startsWith("/")) {
525  m_dataFileName = new FileName(m_labelFileName->path() + "/" + temp.original());
526  }
527  else {
528  m_dataFileName = new FileName(temp);
529  }
530 
531  m_attached = false;
532  m_storesDnData = true;
533 
534  m_dataFile = new QFile(realDataFileName().expanded());
535  }
536  else if (core.hasKeyword("^DnFile")) {
537  FileName dataFileName(core["^DnFile"][0]);
538 
539  if (dataFileName.originalPath() == ".") {
540  m_dataFileName = new FileName(m_labelFileName->path() + "/" + dataFileName.name());
541  }
542  else {
543  m_dataFileName = new FileName(dataFileName);
544  }
545 
546  m_attached = true;
547  m_storesDnData = false;
548 
549  m_dataFile = new QFile(realDataFileName().expanded());
550  }
551  else {
552  m_dataFileName = new FileName(*m_labelFileName);
553  m_attached = true;
554  m_storesDnData = true;
555  }
556  }
557  catch (IException &e) {
558  cleanUp(false);
559  throw;
560  }
561 
562  if (access == "r") {
563  if (!m_labelFile->open(QIODevice::ReadOnly)) {
564  QString msg = "Failed to open [" + m_labelFile->fileName() + "] with "
565  "read only access";
566  cleanUp(false);
567  throw IException(IException::Io, msg, _FILEINFO_);
568  }
569 
570  if (m_dataFile) {
571  if (!m_dataFile->open(QIODevice::ReadOnly)) {
572  QString msg = "Failed to open [" + m_dataFile->fileName() + "] with "
573  "read only access";
574  cleanUp(false);
575  throw IException(IException::Io, msg, _FILEINFO_);
576  }
577  }
578  }
579  else if (access == "rw") {
580  if (!m_labelFile->open(QIODevice::ReadWrite)) {
581  QString msg = "Failed to open [" + m_labelFile->fileName() + "] with "
582  "read/write access";
583  cleanUp(false);
584  throw IException(IException::Io, msg, _FILEINFO_);
585  }
586 
587  if (m_dataFile) {
588  if (m_storesDnData && !m_dataFile->open(QIODevice::ReadWrite)) {
589  QString msg = "Failed to open [" + m_dataFile->fileName() + "] with "
590  "read/write access";
591  cleanUp(false);
592  throw IException(IException::Io, msg, _FILEINFO_);
593  }
594  else if (!m_storesDnData && !m_dataFile->open(QIODevice::ReadOnly)) {
595  QString msg = "Failed to open [" + m_dataFile->fileName() + "] with "
596  "read access";
597  cleanUp(false);
598  throw IException(IException::Io, msg, _FILEINFO_);
599  }
600  }
601  }
602  else {
603  QString msg = "Unknown value for access [" + access + "]. Expected 'r' "
604  " or 'rw'";
605  cleanUp(false);
606  throw IException(IException::Programmer, msg, _FILEINFO_);
607  }
608 
609  initCoreFromLabel(*m_label);
610 
611  // Determine the number of bytes in the label
612  if (m_attached) {
613  m_labelBytes = m_label->findObject("Label")["Bytes"];
614  }
615  else {
616  m_labelBytes = labelSize(true);
617  }
618 
619  QPair<bool, Pvl *> dataLabel = qMakePair(false, m_label);
620  if (!m_storesDnData) {
621  dataLabel = qMakePair(true, new Pvl(m_dataFileName->expanded()));
622  }
623 
624  // Now examine the format to see which type of handler to create
625  if (m_format == Bsq) {
626  m_ioHandler = new CubeBsqHandler(dataFile(), m_virtualBandList,
627  realDataFileLabel(), true);
628  }
629  else {
630  m_ioHandler = new CubeTileHandler(dataFile(), m_virtualBandList,
631  realDataFileLabel(), true);
632  }
633 
634  if (dataLabel.first) {
635  delete dataLabel.second;
636  dataLabel.second = NULL;
637  }
638 
639  applyVirtualBandsToLabel();
640  }
641 
642 
651  void Cube::reopen(QString access) {
652  if (!m_labelFile) {
653  QString msg = "Cube has not been opened yet. The filename to re-open is "
654  "unknown";
655  throw IException(IException::Programmer, msg, _FILEINFO_);
656  }
657 
658  // Preserve filename and virtual bands when re-opening
659  FileName filename = *m_labelFileName;
660  QList<int> virtualBandList;
661 
662  if (m_virtualBandList)
663  virtualBandList = *m_virtualBandList;
664 
665  close();
666  open(filename.expanded(), access);
667 
668  if (virtualBandList.size()) {
669  if (m_virtualBandList)
670  *m_virtualBandList = virtualBandList;
671  else
672  m_virtualBandList = new QList<int>(virtualBandList);
673  }
674  }
675 
676 
684  void Cube::read(Blob &blob) const {
685  if (!isOpen()) {
686  string msg = "The cube is not opened so you can't read a blob from it";
687  throw IException(IException::Programmer, msg, _FILEINFO_);
688  }
689 
690  FileName cubeFile = *m_labelFileName;
691  if (m_tempCube)
692  cubeFile = *m_tempCube;
693 
694  QMutexLocker locker(m_mutex);
695  QMutexLocker locker2(m_ioHandler->dataFileMutex());
696  blob.Read(cubeFile.toString(), *label());
697  }
698 
699 
706  void Cube::read(Buffer &bufferToFill) const {
707  if (!isOpen()) {
708  string msg = "Try opening a file before you read it";
709  throw IException(IException::Programmer, msg, _FILEINFO_);
710  }
711 
712  QMutexLocker locker(m_mutex);
713  m_ioHandler->read(bufferToFill);
714  }
715 
716 
723  void Cube::write(Blob &blob) {
724  if (!isOpen()) {
725  string msg = "The cube is not opened so you can't write a blob to it";
726  throw IException(IException::Programmer, msg, _FILEINFO_);
727  }
728 
729  if (!m_labelFile->isWritable()) {
730  string msg = "The cube must be opened in read/write mode, not readOnly";
731  throw IException(IException::Programmer, msg, _FILEINFO_);
732  }
733 
734  // Write an attached blob
735  if (m_attached) {
736  QMutexLocker locker(m_mutex);
737  QMutexLocker locker2(m_ioHandler->dataFileMutex());
738 
739  // Compute the number of bytes in the cube + label bytes and if the
740  // endpos of the file // is not greater than this then seek to that position.
741  fstream stream(m_labelFileName->expanded().toAscii().data(),
742  ios::in | ios::out | ios::binary);
743  stream.seekp(0, ios::end);
744 
745  // End byte = end byte of the file (aka eof position, file size)
746  streampos endByte = stream.tellp();
747  // maxbyte = position after the cube DN data and labels
748  streampos maxbyte = (streampos) m_labelBytes;
749 
750  if (m_storesDnData) {
751  maxbyte += (streampos) m_ioHandler->getDataSize();
752  }
753 
754  // If EOF is too early, allocate space up to where we want the blob
755  if (endByte < maxbyte) {
756  stream.seekp(maxbyte, ios::beg);
757  }
758 
759  blob.Write(*m_label, stream);
760  }
761 
762  // Write a detached blob
763  else {
764  FileName blobFileName = fileName();
765  blobFileName = blobFileName.removeExtension();
766  blobFileName = blobFileName.addExtension(blob.Type());
767  blobFileName = blobFileName.addExtension(blob.Name());
768  QString blobFile(blobFileName.expanded());
769  ios::openmode flags = ios::in | ios::binary | ios::out | ios::trunc;
770  fstream detachedStream;
771  detachedStream.open(blobFile.toAscii().data(), flags);
772  if (!detachedStream) {
773  QString message = "Unable to open data file [" +
774  blobFileName.expanded() + "]";
775  throw IException(IException::Io, message, _FILEINFO_);
776  }
777 
778 // Changed to work with mods to FileName class
779 // blob.Write(p_cube.label,detachedStream,blobFileName.baseName()+"."+
780 // blob.Type()+"."+
781 // blobFileName.extension());
782  blob.Write(*m_label, detachedStream, blobFileName.name());
783  }
784  }
785 
786 
793  void Cube::write(Buffer &bufferToWrite) {
794  if (!isOpen()) {
795  string msg = "Tried to write to a cube before opening/creating it";
796  throw IException(IException::Programmer, msg, _FILEINFO_);
797  }
798 
799  if (isReadOnly()) {
800  QString msg = "Cannot write to the cube [" + (QString)QFileInfo(fileName()).fileName() +
801  "] because it is opened read-only";
802  throw IException(IException::Programmer, msg, _FILEINFO_);
803  }
804 
805  if (!m_storesDnData) {
806  QString msg = "The cube [" + QFileInfo(fileName()).fileName() +
807  "] does not support storing DN data because it is using an external file for DNs";
808  throw IException(IException::Unknown, msg, _FILEINFO_);
809  }
810 
811  QMutexLocker locker(m_mutex);
812  m_ioHandler->write(bufferToWrite);
813  }
814 
815 
826  void Cube::setBaseMultiplier(double base, double mult) {
827  openCheck();
828  m_base = base;
829  m_multiplier = mult;
830  }
831 
832 
843  void Cube::setMinMax(double min, double max) {
844  openCheck();
845 
846  m_base = 0.0;
847  m_multiplier = 1.0;
848 
849  double x1, x2;
850  if (m_pixelType == UnsignedByte) {
851  x1 = VALID_MIN1;
852  x2 = VALID_MAX1;
853  m_multiplier = (max - min) / (x2 - x1);
854  m_base = min - m_multiplier * x1;
855  }
856  else if (m_pixelType == SignedWord) {
857  x1 = VALID_MIN2;
858  x2 = VALID_MAX2;
859  m_multiplier = (max - min) / (x2 - x1);
860  m_base = min - m_multiplier * x1;
861  }
862  }
863 
864 
871  void Cube::setByteOrder(ByteOrder byteOrder) {
872  openCheck();
873  m_byteOrder = byteOrder;
874  }
875 
876 
886  void Cube::setDimensions(int ns, int nl, int nb) {
887  openCheck();
888  if ((ns < 1) || (nl < 1) || (nb < 1)) {
889  string msg = "SetDimensions: Invalid number of sample, lines or bands";
890  throw IException(IException::Programmer, msg, _FILEINFO_);
891  }
892  m_samples = ns;
893  m_lines = nl;
894  m_bands = nb;
895  }
896 
897 
898  void Cube::setExternalDnData(FileName cubeFileWithDnData) {
899  try {
900  initLabelFromFile(cubeFileWithDnData, false);
901  initCoreFromLabel(*m_label);
902 
903  delete m_label;
904  m_label = NULL;
905  }
906  catch (IException &) {
907  delete m_label;
908  m_label = NULL;
909  throw;
910  }
911 
912  m_storesDnData = false;
913  m_dataFileName = new FileName(cubeFileWithDnData);
914 
915  delete m_labelFile;
916  m_labelFile = NULL;
917 
918  delete m_labelFileName;
919  m_labelFileName = NULL;
920  }
921 
922 
930  void Cube::setFormat(Format format) {
931  openCheck();
932  m_format = format;
933  }
934 
935 
942  void Cube::setLabelsAttached(bool attach) {
943  openCheck();
944  m_attached = attach;
945  }
946 
947 
955  void Cube::setLabelSize(int labelBytes) {
956  openCheck();
957  m_labelBytes = labelBytes;
958  }
959 
960 
968  void Cube::setPixelType(PixelType pixelType) {
969  openCheck();
970  m_pixelType = pixelType;
971  }
972 
973 
985  void Cube::setVirtualBands(const QList<QString> &vbands) {
986  openCheck();
987  if (m_virtualBandList)
988  m_virtualBandList->clear();
989  else
990  m_virtualBandList = new QList<int>;
991 
992  if (vbands.size() > 0) {
993  QListIterator<QString> it(vbands);
994  while (it.hasNext()) {
995  m_virtualBandList->append(toInt(it.next()));
996  }
997  }
998  else {
999  delete m_virtualBandList;
1000  m_virtualBandList = NULL;
1001  }
1002 
1003  if (m_ioHandler) {
1004  m_ioHandler->setVirtualBands(m_virtualBandList);
1005  }
1006  }
1007 
1008 
1015  void Cube::setVirtualBands(const std::vector<QString> &vbands) {
1016  QList<QString> realVBands;
1017 
1018  for(unsigned int i = 0; i < vbands.size(); i++)
1019  realVBands << vbands[i];
1020 
1021  setVirtualBands(realVBands);
1022  }
1023 
1024 
1025  void Cube::relocateDnData(FileName dnDataFile) {
1026  if (!isOpen()) {
1027  throw IException(IException::Unknown,
1028  QString("Cannot relocate the DN data to [%1] for an external cube label "
1029  "file which is not open.")
1030  .arg(dnDataFile.original()),
1031  _FILEINFO_);
1032  }
1033 
1034 
1035  if (m_storesDnData) {
1036  throw IException(IException::Unknown,
1037  QString("The cube [%1] stores DN data. It cannot be relocated to [%2] - "
1038  "this is only supported for external cube label files.")
1039  .arg(m_labelFileName->original()).arg(dnDataFile.original()),
1040  _FILEINFO_);
1041  }
1042 
1043  m_label->findObject("IsisCube").findObject("Core").findKeyword("^DnFile")[0] =
1044  dnDataFile.original();
1045  reopen(m_labelFile->isWritable()? "rw" : "r");
1046  }
1047 
1048 
1049 // void Cube::relocateDnData(FileName externalLabelFile, FileName dnDataFile) {
1050 // try {
1051 // Pvl externalLabelData(externalLabelFile.expanded());
1052 // externalLabelData.FindObject("IsisCube").FindObject("Core").FindKeyword("^DnFile")[0] =
1053 // dnDataFile.original();
1054 // }
1055 // catch (IException &e) {
1056 // throw IException(e, IException::Io,
1057 // QString("File [%1] does not appear to be an external cube label file")
1058 // .arg(externalLabelFile.original().ToQt()),
1059 // _FILEINFO_);
1060 // }
1061 // }
1062 
1063 
1069  int Cube::bandCount() const {
1070  int numBands = m_bands;
1071  if (m_virtualBandList)
1072  numBands = m_virtualBandList->size();
1073  return numBands;
1074  }
1075 
1076 
1086  double Cube::base() const {
1087  return m_base;
1088  }
1089 
1090 
1098  ByteOrder Cube::byteOrder() const {
1099  return m_byteOrder;
1100  }
1101 
1102 
1110  Camera *Cube::camera() {
1111  if (m_camera == NULL && isOpen()) {
1112  m_camera = CameraFactory::Create(*this);
1113  }
1114  return m_camera;
1115  }
1116 
1117 
1124  FileName Cube::externalCubeFileName() const {
1125  if (!isOpen()) {
1126  throw IException(IException::Unknown,
1127  "An external cube label file must be opened in order to use "
1128  "Cube::getExternalCubeFileName",
1129  _FILEINFO_);
1130  }
1131 
1132  if (storesDnData()) {
1133  throw IException(IException::Unknown,
1134  "Cube::getExternalCubeFileName can only be called on an external cube label "
1135  "file",
1136  _FILEINFO_);
1137  }
1138 
1139 
1140  PvlObject &core = m_label->findObject("IsisCube").findObject("Core");
1141 
1142  return core["^DnFile"][0];
1143  }
1144 
1145 
1152  QString Cube::fileName() const {
1153  if (isOpen())
1154  return m_labelFileName->expanded();
1155  else
1156  return "";
1157  }
1158 
1159 
1164  Cube::Format Cube::format() const {
1165  return m_format;
1166  }
1167 
1168 
1188  Histogram *Cube::histogram(const int &band, QString msg) {
1189  return histogram(band, ValidMinimum, ValidMaximum, msg);
1190  }
1191 
1192 
1218  Histogram *Cube::histogram(const int &band, const double &validMin,
1219  const double &validMax, QString msg) {
1220  // Make sure cube is open
1221  if ( !isOpen() ) {
1222  QString msg = "Cannot create histogram object for an unopened cube";
1223  throw IException(IException::Programmer, msg, _FILEINFO_);
1224  }
1225 
1226  // Make sure band is valid
1227  if ((band < 0) || (band > bandCount())) {
1228  QString msg = "Invalid band in [CubeInfo::Histogram]";
1229  throw IException(IException::Programmer, msg, _FILEINFO_);
1230  }
1231 
1232  int bandStart = band;
1233  int bandStop = band;
1234  int maxSteps = lineCount();
1235  if (band == 0) {
1236  bandStart = 1;
1237  bandStop = bandCount();
1238  maxSteps = lineCount() * bandCount();
1239  }
1240 
1241  Progress progress;
1242  Histogram *hist = new Histogram(*this, band, &progress);
1243  LineManager line(*this);
1244 
1245  // This range is for throwing out data; the default parameters are OK always
1246  hist->SetValidRange(validMin, validMax);
1247 
1248  // We now need to know the binning range - ValidMinimum/Maximum are no longer
1249  // acceptable, default to the bin range start/end.
1250  double binMin = validMin;
1251  double binMax = validMax;
1252  if (binMin == ValidMinimum) {
1253  binMin = hist->BinRangeStart();
1254  }
1255 
1256  if (binMax == ValidMaximum) {
1257  binMax = hist->BinRangeEnd();
1258  }
1259 
1260  hist->SetBinRange(binMin, binMax);
1261 
1262  // Loop and get the histogram
1263  progress.SetText(msg);
1264  progress.SetMaximumSteps(maxSteps);
1265  progress.CheckStatus();
1266 
1267  for(int useBand = bandStart ; useBand <= bandStop ; useBand++) {
1268  for(int i = 1; i <= lineCount(); i++) {
1269  line.SetLine(i, useBand);
1270  read(line);
1271  hist->AddData(line.DoubleBuffer(), line.size());
1272  progress.CheckStatus();
1273  }
1274  }
1275 
1276  return hist;
1277  }
1278 
1279 
1289  Pvl *Cube::label() const {
1290  return m_label;
1291  }
1292 
1293 
1301  int Cube::labelSize(bool actual) const {
1302  int labelSize = m_labelBytes;
1303 
1304  if (actual && m_label) {
1305  ostringstream s;
1306  s << *m_label << endl;
1307  labelSize = s.tellp();
1308  }
1309  else if (actual) {
1310  labelSize = 0;
1311  }
1312 
1313  return labelSize;
1314  }
1315 
1316 
1322  int Cube::lineCount() const {
1323  return m_lines;
1324  }
1325 
1326 
1336  double Cube::multiplier() const {
1337  return m_multiplier;
1338  }
1339 
1340 
1346  PixelType Cube::pixelType() const {
1347  return m_pixelType;
1348  }
1349 
1350 
1361  int Cube::physicalBand(const int &virtualBand) const {
1362  int physicalBand = virtualBand;
1363 
1364  if (m_virtualBandList) {
1365  if ((virtualBand < 1) ||
1366  (virtualBand > m_virtualBandList->size())) {
1367  QString msg = "Out of array bounds [" + toString(virtualBand) + "]";
1368  throw IException(IException::Programmer, msg, _FILEINFO_);
1369  }
1370  physicalBand = m_virtualBandList->at(virtualBand - 1);
1371  }
1372 
1373  return physicalBand;
1374  }
1375 
1376 
1382  Projection *Cube::projection() {
1383  if (m_projection == NULL && isOpen()) {
1384  m_projection = ProjectionFactory::CreateFromCube(*label());
1385  }
1386  return m_projection;
1387  }
1388 
1389 
1395  int Cube::sampleCount() const {
1396  return m_samples;
1397  }
1398 
1399 
1418  Statistics *Cube::statistics(const int &band, QString msg) {
1419  return statistics(band, ValidMinimum, ValidMaximum, msg);
1420  }
1421 
1422 
1439  Statistics *Cube::statistics(const int &band, const double &validMin,
1440  const double &validMax, QString msg) {
1441  // Make sure cube is open
1442  if ( !isOpen() ) {
1443  QString msg = "Cannot create statistics object for an unopened cube";
1444  throw IException(IException::Programmer, msg, _FILEINFO_);
1445  }
1446 
1447  // Make sure band is valid
1448  if ((band < 0) || (band > bandCount())) {
1449  string msg = "Invalid band in [CubeInfo::Statistics]";
1450  throw IException(IException::Programmer, msg, _FILEINFO_);
1451  }
1452 
1453  // Construct a line buffer manager and a statistics object
1454  LineManager line(*this);
1455  Statistics *stats = new Statistics();
1456 
1457  stats->SetValidRange(validMin, validMax);
1458 
1459  int bandStart = band;
1460  int bandStop = band;
1461  int maxSteps = lineCount();
1462  if (band == 0) {
1463  bandStart = 1;
1464  bandStop = bandCount();
1465  maxSteps = lineCount() * bandCount();
1466  }
1467 
1468  Progress progress;
1469  progress.SetText(msg);
1470  progress.SetMaximumSteps(maxSteps);
1471  progress.CheckStatus();
1472 
1473  // Loop and get the statistics for a good minimum/maximum
1474  for(int useBand = bandStart ; useBand <= bandStop ; useBand++) {
1475  for(int i = 1; i <= lineCount(); i++) {
1476  line.SetLine(i, useBand);
1477  read(line);
1478  stats->AddData(line.DoubleBuffer(), line.size());
1479  progress.CheckStatus();
1480  }
1481  }
1482 
1483  return stats;
1484  }
1485 
1486 
1487  bool Cube::storesDnData() const {
1488  return m_storesDnData;
1489  }
1490 
1491 
1505  void Cube::addCachingAlgorithm(CubeCachingAlgorithm *algorithm) {
1506 
1507  if (isOpen() && m_ioHandler) {
1508  m_ioHandler->addCachingAlgorithm(algorithm);
1509  }
1510  else if (!isOpen()) {
1511  QString msg = "Cannot add a caching algorithm until the cube is open";
1512  throw IException(IException::Programmer, msg, _FILEINFO_);
1513  }
1514  }
1515 
1521  void Cube::clearIoCache() {
1522  if (m_ioHandler) {
1523  QMutexLocker locker(m_mutex);
1524  m_ioHandler->clearCache();
1525  }
1526  }
1527 
1528 
1538  bool Cube::deleteBlob(QString BlobType, QString BlobName) {
1539  for(int i = 0; i < m_label->objects(); i++) {
1540  PvlObject obj = m_label->object(i);
1541  if (obj.name().compare(BlobType) == 0) {
1542  if (obj.findKeyword("Name")[0] == BlobName) {
1543  m_label->deleteObject(i);
1544  return true;
1545  }
1546  }
1547  }
1548  return false;
1549  }
1550 
1551 
1560  void Cube::deleteGroup(const QString &group) {
1561  PvlObject &isiscube = label()->findObject("IsisCube");
1562  if (!isiscube.hasGroup(group)) return;
1563  isiscube.deleteGroup(group);
1564  }
1565 
1566 
1574  PvlGroup &Cube::group(const QString &group) const {
1575  PvlObject &isiscube = label()->findObject("IsisCube");
1576  return isiscube.findGroup(group);
1577  }
1578 
1579 
1587  bool Cube::hasGroup(const QString &group) const {
1588  const PvlObject &isiscube = label()->findObject("IsisCube");
1589  if (isiscube.hasGroup(group)) return true;
1590  return false;
1591  }
1592 
1593 
1601  bool Cube::hasTable(const QString &name) {
1602  for(int o = 0; o < label()->objects(); o++) {
1603  PvlObject &obj = label()->object(o);
1604  if (obj.isNamed("Table")) {
1605  if (obj.hasKeyword("Name")) {
1606  QString temp = (QString) obj["Name"];
1607  temp = temp.toUpper();
1608  QString temp2 = name;
1609  temp2 = temp2.toUpper();
1610  if (temp == temp2) return true;
1611  }
1612  }
1613  }
1614  return false;
1615  }
1616 
1617 
1626  void Cube::putGroup(const PvlGroup &group) {
1627  PvlObject &isiscube = label()->findObject("IsisCube");
1628  if (isiscube.hasGroup(group.name())) {
1629  isiscube.findGroup(group.name()) = group;
1630  }
1631  else {
1632  isiscube.addGroup(group);
1633  }
1634  }
1635 
1636 
1637  void Cube::applyVirtualBandsToLabel() {
1638  PvlObject &core = m_label->findObject("IsisCube").findObject("Core");
1639 
1640  // Prune the band bin group if it exists
1641  if (m_label->findObject("IsisCube").hasGroup("BandBin")) {
1642  PvlGroup &bandBin = m_label->findObject("IsisCube").findGroup("BandBin");
1643  for (int k = 0;k < bandBin.keywords();k++) {
1644  if (bandBin[k].size() == m_bands && m_virtualBandList) {
1645  PvlKeyword temp = bandBin[k];
1646  bandBin[k].clear();
1647  for (int i = 0;i < m_virtualBandList->size();i++) {
1648  int physicalBand = m_virtualBandList->at(i) - 1;
1649  bandBin[k].addValue(temp[physicalBand], temp.unit(physicalBand));
1650  }
1651  }
1652  }
1653  }
1654 
1655  // Change the number of bands in the labels of the cube
1656  if (m_virtualBandList && core.hasGroup("Dimensions")) core.findGroup("Dimensions")["Bands"] = toString(m_virtualBandList->size());
1657  }
1658 
1659 
1665  void Cube::cleanUp(bool removeIt) {
1666  if (m_ioHandler) {
1667  delete m_ioHandler;
1668  m_ioHandler = NULL;
1669  }
1670 
1671  // Always remove a temporary file
1672  if (m_tempCube) {
1673  QFile::remove(m_tempCube->expanded());
1674  removeIt = false; // dont remove originals
1675 
1676  delete m_tempCube;
1677  m_tempCube = NULL;
1678  }
1679 
1680  if (removeIt) {
1681  QFile::remove(m_labelFileName->expanded());
1682 
1683  if (*m_labelFileName != *m_dataFileName)
1684  QFile::remove(m_dataFileName->expanded());
1685  }
1686 
1687  delete m_labelFile;
1688  m_labelFile = NULL;
1689 
1690  delete m_dataFile;
1691  m_dataFile = NULL;
1692 
1693  delete m_labelFileName;
1694  m_labelFileName = NULL;
1695 
1696  delete m_dataFileName;
1697  m_dataFileName = NULL;
1698 
1699  delete m_label;
1700  m_label = NULL;
1701 
1702  delete m_virtualBandList;
1703  m_virtualBandList = NULL;
1704 
1705  initialize();
1706  }
1707 
1708 
1713  void Cube::construct() {
1714  m_labelFile = NULL;
1715  m_dataFile = NULL;
1716  m_ioHandler = NULL;
1717  m_mutex = NULL;
1718 
1719  m_camera = NULL;
1720  m_projection = NULL;
1721 
1722  m_labelFileName = NULL;
1723  m_dataFileName = NULL;
1724  m_tempCube = NULL;
1725  m_formatTemplateFile = NULL;
1726  m_label = NULL;
1727 
1728  m_virtualBandList = NULL;
1729 
1730  m_mutex = new QMutex();
1731  m_formatTemplateFile =
1732  new FileName("$base/templates/labels/CubeFormatTemplate.pft");
1733 
1734  initialize();
1735  }
1736 
1737 
1744  QFile *Cube::dataFile() const {
1745  if (m_dataFile)
1746  return m_dataFile;
1747  else
1748  return m_labelFile;
1749  }
1750 
1751 
1757  FileName Cube::realDataFileName() const {
1758  FileName result;
1759 
1760  // Attached, stores DN data - normal cube
1761  if (m_attached && m_storesDnData) {
1762  ASSERT(m_labelFileName);
1763  result = *m_labelFileName;
1764  }
1765  // Detached, stores DN data - standard detached cube
1766  else if (!m_attached && m_storesDnData) {
1767  ASSERT(m_dataFileName);
1768  result = *m_dataFileName;
1769  }
1770  // External cube - go look at our external file
1771  else if (!m_storesDnData) {
1772  ASSERT(m_dataFileName);
1773  FileName guess = *m_dataFileName;
1774 
1775  do {
1776  Pvl guessLabel(guess.expanded());
1777 
1778  PvlObject &core = guessLabel.findObject("IsisCube").findObject("Core");
1779 
1780  if (core.hasKeyword("^DnFile")) {
1781  FileName currentGuess = guess;
1782  guess = core["^DnFile"][0];
1783 
1784  if (!guess.path().startsWith("/")) {
1785  guess = currentGuess.path() + "/" + guess.original();
1786  }
1787  }
1788  else if (core.hasKeyword("^Core")) {
1789  result = core["^Core"][0];
1790  }
1791  else {
1792  result = guess;
1793  }
1794  }
1795  while (result.name() == "");
1796  }
1797 
1798  return result;
1799  }
1800 
1801 
1813  void Cube::initialize() {
1814  m_byteOrder = Lsb;
1815  if (IsBigEndian())
1816  m_byteOrder = Msb;
1817  m_format = Tile;
1818  m_pixelType = Real;
1819 
1820  m_attached = true;
1821  m_storesDnData = true;
1822  m_labelBytes = 65536;
1823 
1824  m_samples = 0;
1825  m_lines = 0;
1826  m_bands = 0;
1827 
1828  m_base = 0.0;
1829  m_multiplier = 1.0;
1830  }
1831 
1832 
1833  void Cube::initCoreFromLabel(const Pvl &label) {
1834  const PvlObject &core = label.findObject("IsisCube").findObject("Core");
1835 
1836  if (!core.hasKeyword("^DnFile")) {
1837  // Dimensions
1838  const PvlGroup &dims = core.findGroup("Dimensions");
1839  m_samples = dims["Samples"];
1840  m_lines = dims["Lines"];
1841  m_bands = dims["Bands"];
1842 
1843  // Stored pixel information
1844  const PvlGroup &pixelsGroup = core.findGroup("Pixels");
1845  m_byteOrder = ByteOrderEnumeration(pixelsGroup["ByteOrder"]);
1846  m_base = pixelsGroup["Base"];
1847  m_multiplier = pixelsGroup["Multiplier"];
1848  m_pixelType = PixelTypeEnumeration(pixelsGroup["Type"]);
1849 
1850  // Now examine the format to see which type of handler to create
1851  if ((QString) core["Format"] == "BandSequential") {
1852  m_format = Bsq;
1853  }
1854  else {
1855  m_format = Tile;
1856  }
1857  }
1858  else {
1859  FileName temp(core["^DnFile"][0]);
1860  if (!temp.expanded().startsWith("/")) {
1861  temp = FileName(m_labelFileName->path() + "/" + temp.original());
1862  }
1863 
1864  initCoreFromLabel(Pvl(temp.toString()));
1865  }
1866  }
1867 
1868 
1869  void Cube::initLabelFromFile(FileName labelFileName, bool readWrite) {
1870  ASSERT(!m_labelFileName);
1871 
1872  try {
1873  if (labelFileName.fileExists()) {
1874  m_label = new Pvl(labelFileName.expanded());
1875  if (!m_label->objects()) {
1876  throw IException();
1877  }
1878  }
1879  }
1880  catch(IException &) {
1881  if (m_label) {
1882  delete m_label;
1883  m_label = NULL;
1884  }
1885  }
1886 
1887  try {
1888  if (!m_label) {
1889  FileName tmp(labelFileName);
1890  tmp = tmp.addExtension("cub");
1891  if (tmp.fileExists()) {
1892  m_label = new Pvl(tmp.expanded());
1893  if (!m_label->objects()) {
1894  throw IException();
1895  }
1896  labelFileName = tmp;
1897  }
1898  }
1899  }
1900  catch(IException &e) {
1901  if (m_label) {
1902  delete m_label;
1903  m_label = NULL;
1904  }
1905  }
1906 
1907  try {
1908  if (!m_label) {
1909  FileName tmp(labelFileName);
1910  tmp = tmp.setExtension("lbl");
1911  if (tmp.fileExists()) {
1912  m_label = new Pvl(tmp.expanded());
1913  if (!m_label->objects()) {
1914  throw IException();
1915  }
1916  labelFileName = tmp;
1917  }
1918  }
1919  }
1920  catch(IException &e) {
1921  if (m_label) {
1922  delete m_label;
1923  m_label = NULL;
1924  }
1925  }
1926 
1927  try {
1928  if (!m_label) {
1929  FileName tmp(labelFileName);
1930  tmp = tmp.addExtension("ecub");
1931  if (tmp.fileExists()) {
1932  m_label = new Pvl(tmp.expanded());
1933  if (!m_label->objects()) {
1934  throw IException();
1935  }
1936  labelFileName = tmp;
1937  }
1938  }
1939  }
1940  catch(IException &e) {
1941  if (m_label) {
1942  delete m_label;
1943  m_label = NULL;
1944  }
1945  }
1946 
1947  if (!m_label) {
1948  QString msg = Message::FileOpen(labelFileName.original());
1949  throw IException(IException::Io, msg, _FILEINFO_);
1950  }
1951 
1952  m_labelFileName = new FileName(labelFileName);
1953 
1954  // See if this is an old Isis cube format. If so then we will
1955  // need to internalize a new label
1956  if (m_label->hasKeyword("CCSD3ZF0000100000001NJPL3IF0PDS200000001")) {
1957  if (!readWrite) {
1958  reformatOldIsisLabel(m_labelFileName->expanded());
1959  }
1960  else {
1961  cleanUp(false);
1962  QString msg = "Can not open old cube file format with write access [" +
1963  m_labelFileName->original() + "]";
1964  throw IException(IException::Io, msg, _FILEINFO_);
1965  }
1966  }
1967  else {
1968  m_labelFile = new QFile(m_labelFileName->expanded());
1969  }
1970  }
1971 
1972 
1976  void Cube::openCheck() {
1977  if (isOpen()) {
1978  string msg = "Sorry you can't do a SetMethod after the cube is opened";
1979  throw IException(IException::Programmer, msg, _FILEINFO_);
1980  }
1981  }
1982 
1983  Pvl Cube::realDataFileLabel() const {
1984  Pvl label = *m_label;
1985  PvlObject *core = NULL;
1986 
1987  do {
1988  core = &label.findObject("IsisCube").findObject("Core");
1989 
1990  if (core->hasKeyword("^DnFile")) {
1991 
1992  FileName temp((*core)["^DnFile"][0]);
1993  if (!temp.expanded().startsWith("/")) {
1994  temp = FileName(FileName(label.fileName()).path() + "/" + temp.original());
1995  }
1996 
1997  label = Pvl(temp.toString());
1998  core = NULL;
1999  }
2000  }
2001  while (!core);
2002 
2003  return label;
2004  }
2005 
2006 
2013  void Cube::reformatOldIsisLabel(const QString &oldCube) {
2014  QString parameters = "from=" + oldCube;
2015  FileName oldName(oldCube);
2016  FileName tempCube = FileName::createTempFile("Temporary_" + oldName.name() + ".cub");
2017  parameters += " to=" + tempCube.expanded();
2018 
2019  if (iApp == NULL) {
2020  QString command = "$ISISROOT/bin/pds2isis " + parameters;
2021  ProgramLauncher::RunSystemCommand(command);
2022  }
2023  else {
2024  QString prog = "pds2isis";
2025  ProgramLauncher::RunIsisProgram(prog, parameters);
2026  }
2027 
2028  m_tempCube = new FileName(tempCube);
2029  *m_label = Pvl(m_tempCube->toString());
2030  m_labelFile = new QFile(m_tempCube->expanded());
2031  }
2032 
2033 
2038  void Cube::writeLabels() {
2039  if (!isOpen()) {
2040  string msg = "Cube must be opened first before writing labels";
2041  throw IException(IException::Programmer, msg, _FILEINFO_);
2042  }
2043 
2044  // Set the pvl's format template
2045  m_label->setFormatTemplate(m_formatTemplateFile->original());
2046 
2047  // Write them with attached data
2048  if (m_attached) {
2049  QMutexLocker locker(m_mutex);
2050  QMutexLocker locker2(m_ioHandler->dataFileMutex());
2051 
2052  ostringstream temp;
2053  temp << *m_label << endl;
2054  string tempstr = temp.str();
2055  if ((int) tempstr.length() < m_labelBytes) {
2056  QByteArray labelArea(m_labelBytes, '\0');
2057  QByteArray labelUnpaddedContents(tempstr.c_str(), tempstr.length());
2058  labelArea.replace(0, labelUnpaddedContents.size(), labelUnpaddedContents);
2059  // Rewrite the label area
2060  m_labelFile->seek(0);
2061  m_labelFile->write(labelArea);
2062  }
2063  else {
2064  locker2.unlock();
2065  QString msg = "Label space is full in [" +
2066  (QString)FileName(*m_labelFileName).name() +
2067  "] unable to write labels";
2068  cleanUp(false);
2069  throw IException(IException::Io, msg, _FILEINFO_);
2070  }
2071  }
2072 
2073  // or detached label
2074  else {
2075  m_label->write(m_labelFileName->expanded());
2076  }
2077  }
2078 }