Isis 3 Programmer Reference
Blob.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "Blob.h"
8 
9 #include <cstring>
10 #include <fstream>
11 #include <sstream>
12 
13 #include <QDebug>
14 
15 #include "FileName.h"
16 #include "IException.h"
17 #include "Message.h"
18 #include "Pvl.h"
19 
20 using namespace std;
21 namespace Isis {
28  Blob::Blob(const QString &name, const QString &type) {
29  p_blobName = name;
30  p_buffer = NULL;
31  p_labelFile = "";
32  p_nbytes = 0;
33  p_type = type;
34 
35  p_blobPvl.setName(p_type);
36  p_blobPvl += PvlKeyword("Name", p_blobName);
37  p_blobPvl += PvlKeyword("StartByte", "0");
38  p_blobPvl += PvlKeyword("Bytes", "0");
39  }
40 
49  Blob::Blob(const QString &name, const QString &type,
50  const QString &file) {
51  p_blobName = name;
52  p_buffer = NULL;
53  p_nbytes = 0;
54  p_type = type;
55  p_labelFile = FileName(file).expanded();
56 
57  Read(file);
58  }
59 
65  Blob::Blob(const Blob &other) {
66  p_blobPvl = other.p_blobPvl;
67  p_blobName = other.p_blobName;
68  p_startByte = other.p_startByte;
69  p_nbytes = other.p_nbytes;
70  p_type = other.p_type;
71  p_detached = other.p_detached;
72  p_labelFile = other.p_labelFile;
73 
74  p_buffer = NULL;
75 
76  if (other.p_buffer) {
77  p_buffer = new char[p_nbytes];
78 
79  for (int i = 0; i < p_nbytes; i++) {
80  p_buffer[i] = other.p_buffer[i];
81  }
82  }
83  }
84 
92  Blob &Blob::operator=(const Blob &other) {
93  p_blobPvl = other.p_blobPvl;
94  p_blobName = other.p_blobName;
95  p_startByte = other.p_startByte;
96  p_nbytes = other.p_nbytes;
97  p_type = other.p_type;
98  p_detached = other.p_detached;
99  p_labelFile = other.p_labelFile;
100 
101  p_buffer = NULL;
102 
103  if (other.p_buffer) {
104  p_buffer = new char[p_nbytes];
105 
106  for (int i = 0; i < p_nbytes; i++) {
107  p_buffer[i] = other.p_buffer[i];
108  }
109  }
110 
111  return *this;
112  }
113 
115  Blob::~Blob() {
116  if (p_buffer != NULL) delete [] p_buffer;
117  }
118 
124  QString Blob::Type() const {
125  return p_type;
126  }
127 
133  QString Blob::Name() const {
134  return p_blobName;
135  }
136 
142  int Blob::Size() const {
143  return p_nbytes;
144  }
145 
151  PvlObject &Blob::Label() {
152  return p_blobPvl;
153  }
154 
167  void Blob::Find(const Pvl &pvl, const std::vector<PvlKeyword> keywords) {
168  bool found = false;
169  try {
170  // Search for the blob name
171  QString blobName = p_blobName.toUpper();
172  for (int o = 0; o < pvl.objects(); o++) {
173  const PvlObject &obj = pvl.object(o);
174  if (obj.isNamed(p_type)) {
175  QString curName = obj["Name"];
176  curName = curName.toUpper();
177  if (blobName == curName) {
178  // If there are keywords supplied, check that those match, too!
179  if (!keywords.empty()){
180  bool keywordFound = true;
181  for (PvlKeyword keyword : keywords) {
182  if (obj.hasKeyword(keyword.name())) {
183  PvlKeyword blobKeyword = obj.findKeyword(keyword.name());
184  if (blobKeyword == keyword && !blobKeyword.isEquivalent(keyword[0])) {
185  keywordFound = false;
186  break;
187  }
188  }
189  else {
190  keywordFound = false;
191  break;
192  }
193  }
194  if (keywordFound) {
195  p_blobPvl = obj;
196  found = true;
197  break;
198  }
199  }
200  else {
201  p_blobPvl = obj;
202  found = true;
203  break;
204  }
205  }
206  else {
207  if (p_type == "OriginalLabel" && curName == "ORIGINALLABEL") {
208  p_blobPvl = obj;
209  found = true;
210  break;
211  }
212  }
213  }
214  }
215  }
216  catch (IException &e) {
217  QString msg = "Invalid " + p_type + " label format";
218  throw IException(e, IException::Unknown, msg, _FILEINFO_);
219  }
220 
221  // Did we find it?
222  if (!found) {
223  QString msg = "Unable to find " + p_type + " [" + p_blobName + "]";
224  throw IException(IException::Programmer, msg, _FILEINFO_);
225  }
226 
227  // Ok the blob exists so we need to prep for reading the binary data
228  try {
229  p_startByte = p_blobPvl["StartByte"];
230  p_nbytes = p_blobPvl["Bytes"];
231  p_detached = "";
232  if (p_blobPvl.hasKeyword("^" + p_type)) {
233  QString path = "";
234  if (p_labelFile != "") {
235  path = FileName(p_labelFile).path() + "/";
236  }
237  p_detached = path + (QString) p_blobPvl["^"+p_type];
238  p_blobPvl.deleteKeyword("^" + p_type);
239  }
240  }
241  catch (IException &e) {
242  QString msg = "Invalid " + p_type + " label format";
243  throw IException(e, IException::Unknown, msg, _FILEINFO_);
244  }
245  }
246 
255  void Blob::Read(const QString &file, const std::vector<PvlKeyword> keywords) {
256  // Expand the filename
257  QString temp(FileName(file).expanded());
258 
259  // Get the pvl
260  Pvl pvl;
261  try {
262  pvl.read(temp);
263  }
264  catch (IException &e) {
265  QString msg = "Invalid " + p_type + " label format";
266  throw IException(e, IException::Unknown, msg, _FILEINFO_);
267  }
268  Read(file, pvl, keywords);
269  }
270 
279  void Blob::Read(const QString &file, const Pvl &pvlLabels, const std::vector<PvlKeyword> keywords) {
280  // Expand the filename
281  QString temp(FileName(file).expanded());
282 
283  // Open the file
284  fstream istm;
285  istm.open(temp.toLatin1().data(), std::ios::in);
286  if (!istm) {
287  QString message = Message::FileOpen(temp);
288  throw IException(IException::Io, message, _FILEINFO_);
289  }
290 
291  try {
292  // Check pvl and read from the stream
293  Read(pvlLabels, istm, keywords);
294  }
295  catch (IException &e) {
296  istm.close();
297  QString msg = "Unable to open " + p_type + " [" + p_blobName +
298  "] in file [" + temp + "]";
299  throw IException(e, IException::Io, msg, _FILEINFO_);
300  }
301 
302  istm.close();
303  }
304 
313  void Blob::Read(const Pvl &pvl, std::istream &istm, const std::vector<PvlKeyword> keywords){
314  try {
315  Find(pvl, keywords);
316  ReadInit();
317  if (p_detached != "") {
318  fstream dstm;
319  dstm.open(p_detached.toLatin1().data(), std::ios::in);
320  if (!dstm) {
321  QString message = Message::FileOpen(p_detached);
322  throw IException(IException::Io, message, _FILEINFO_);
323  }
324  ReadData(dstm);
325  }
326  else {
327  ReadData(istm);
328  }
329  }
330  catch (IException &e) {
331  QString msg = "Unable to read " + p_type + " [" + p_blobName + "]";
332  throw IException(e, IException::Io, msg, _FILEINFO_);
333  }
334  }
335 
336 
341  void Blob::ReadInit(){
342  }
343 
351  void Blob::ReadData(std::istream &stream) {
352  // Read the binary data
353  if (p_buffer != NULL) delete [] p_buffer;
354  p_buffer = new char[p_nbytes];
355 
356  streampos sbyte = p_startByte - 1;
357  stream.seekg(sbyte, std::ios::beg);
358  if (!stream.good()) {
359  QString msg = "Error preparing to read data from " + p_type +
360  " [" + p_blobName + "]";
361  throw IException(IException::Io, msg, _FILEINFO_);
362  }
363 
364  stream.read(p_buffer, p_nbytes);
365  if (!stream.good()) {
366  QString msg = "Error reading data from " + p_type + " [" + p_blobName + "]";
367  throw IException(IException::Io, msg, _FILEINFO_);
368  }
369  }
370 
371 
382  void Blob::setData(const char *buffer, int nbytes) {
383  char *buf = new char[nbytes];
384  memcpy(buf, buffer, nbytes);
385  takeData(buf, nbytes);
386  }
387 
388 
398  void Blob::takeData(char *buffer, int nbytes) {
399  p_nbytes = nbytes;
400 
401  if (p_buffer != NULL) {
402  delete [] p_buffer;
403  }
404 
405  p_buffer = buffer;
406  }
407 
417  void Blob::Write(const QString &file) {
418  // Determine the size of the label and write it out
419  try {
420  WriteInit();
421  Pvl pvl;
422  pvl.addObject(p_blobPvl);
423  ostringstream os;
424  os << pvl << endl;
425  os.seekp(0, std::ios::end);
426  BigInt nbytes = (BigInt) os.tellp() + (BigInt) 64;
427  p_startByte = nbytes + 1 + 1; // 1-based;
428  pvl.findObject(p_type)["StartByte"] = toString(p_startByte);
429  pvl.findObject(p_type)["Bytes"] = toString(p_nbytes);
430  pvl.write(file);
431 
432  // Prepare and write the binary data
433  fstream stream;
434  ios::openmode flags = std::ios::in | std::ios::binary | std::ios::out;
435  stream.open(file.toLatin1().data(), flags);
436  if (!stream) {
437  QString message = "Unable to open [" + file + "]";
438  throw IException(IException::Io, message, _FILEINFO_);
439  }
440 
441  streampos sbyte = p_startByte - 1;
442  stream.seekp(sbyte, std::ios::beg);
443  if (!stream.good()) {
444  stream.close();
445  QString msg = "Error preparing to write data to " +
446  p_type + " [" + p_blobName + "]";
447  throw IException(IException::Io, msg, _FILEINFO_);
448  }
449 
450  WriteData(stream);
451  stream.close();
452  }
453  catch (IException &e) {
454  QString msg = "Unable to create " + p_type + " file [" + file + "]";
455  throw IException(e, IException::Io, msg, _FILEINFO_);
456  }
457  }
458 
466  void Blob::Write(Pvl &pvl, std::fstream &stm,
467  const QString &detachedFileName, bool overwrite) {
468  // Handle 64-bit I/O
469  WriteInit();
470 
471  // Find out where they wanted to write the blob
472  streampos sbyte = stm.tellp();
473  sbyte += 1;
474 
475  // Find out where the end-of-file is
476  stm.seekp(0, std::ios::end);
477  streampos eofbyte = stm.tellp();
478  eofbyte += 1;
479 
480  // Handle detached blobs
481  if (detachedFileName != "") {
482  p_blobPvl += PvlKeyword("^" + p_type, detachedFileName);
483  }
484 
485 
486  p_blobPvl["StartByte"] = toString((BigInt)sbyte);
487  p_blobPvl["Bytes"] = toString(p_nbytes);
488 
489 
490  // See if the blob is already in the file
491  bool found = false;
492  if (overwrite) {
493 
494  for (int i = 0; i < pvl.objects(); i++) {
495  if (pvl.object(i).name() == p_blobPvl.name()) {
496  PvlObject &obj = pvl.object(i);
497  if ((QString)obj["Name"] == (QString)p_blobPvl["Name"]) {
498  found = true;
499 
500  BigInt oldSbyte = obj["StartByte"];
501  int oldNbytes = (int) obj["Bytes"];
502 
503  // Does it fit in the old space
504  if (p_nbytes <= oldNbytes) {
505  p_blobPvl["StartByte"] = obj["StartByte"];
506  sbyte = oldSbyte;
507  }
508 
509  // Was the old space at the end of the file
510  else if (((oldSbyte + oldNbytes) == eofbyte) &&
511  (eofbyte >= sbyte)) {
512  p_blobPvl["StartByte"] = obj["StartByte"];
513  sbyte = oldSbyte;
514  }
515 
516  // Put it at the requested position/end of the file
517  else {
518  // Leave this here for clarity
519  }
520 
521  obj = p_blobPvl;
522  }
523  }
524  }
525  }
526 
527  // Didn't find the same blob, or don't want to overwrite, so add it to the labels
528  if (!found || !overwrite) {
529  pvl.addObject(p_blobPvl);
530  }
531 
532  stm.seekp((BigInt) sbyte - (BigInt)1);
533  WriteData(stm);
534 
535  // Handle detached blobs
536  if (detachedFileName != "") {
537  p_blobPvl.deleteKeyword("^" + p_type);
538  }
539  }
540 
546  char *Blob::getBuffer() {
547  return p_buffer;
548  }
549 
554  void Blob::WriteInit(){
555  }
556 
564  void Blob::WriteData(std::fstream &stream) {
565  stream.write(p_buffer, p_nbytes);
566  if (!stream.good()) {
567  QString msg = "Error writing data to " + p_type + " [" + p_blobName + "]";
568  throw IException(IException::Io, msg, _FILEINFO_);
569  }
570  }
571 
572 
580  bool IsBlob(PvlObject &obj) {
581  if (obj.isNamed("TABLE")) return true;
582  return false;
583  }
584 } // end namespace isis
Isis::IsBlob
bool IsBlob(PvlObject &obj)
Checks pvl object and returns whether or not it is a Blob.
Definition: Blob.cpp:580
Isis::Blob::p_startByte
BigInt p_startByte
Byte blob data starts at in buffer.
Definition: Blob.h:94
Isis::PvlObject
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:61
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::FileName
File name manipulation and expansion.
Definition: FileName.h:100
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::PvlObject::objects
int objects() const
Returns the number of objects.
Definition: PvlObject.h:219
Isis::PvlObject::addObject
void addObject(const PvlObject &object)
Add a PvlObject.
Definition: PvlObject.h:307
Isis::Pvl::write
void write(const QString &file)
Opens and writes PVL information to a file and handles the end of line sequence.
Definition: Pvl.cpp:130
Isis::Blob::p_labelFile
QString p_labelFile
The file containing the labels.
Definition: Blob.h:98
Isis::PvlObject::object
PvlObject & object(const int index)
Return the object at the specified index.
Definition: PvlObject.cpp:489
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::Blob::p_blobPvl
PvlObject p_blobPvl
Pvl Blob object.
Definition: Blob.h:90
Isis::FileName::expanded
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition: FileName.cpp:196
Isis::Pvl::read
void read(const QString &file)
Loads PVL information from a stream.
Definition: Pvl.cpp:90
Isis::PvlContainer::isNamed
bool isNamed(const QString &match) const
Returns whether the given string is equal to the container name or not.
Definition: PvlContainer.h:72
Isis::PvlObject::hasKeyword
bool hasKeyword(const QString &kname, FindOptions opts) const
See if a keyword is in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within ...
Definition: PvlObject.cpp:236
Isis::BigInt
long long int BigInt
Big int.
Definition: Constants.h:49
Isis::PvlObject::findObject
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Definition: PvlObject.h:274
Isis::Blob::p_detached
QString p_detached
Used for reading detached blobs.
Definition: Blob.h:97
Isis::PvlContainer::name
QString name() const
Returns the container name.
Definition: PvlContainer.h:63
Isis::Blob::p_type
QString p_type
Type of data stored in the buffer.
Definition: Blob.h:96
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Blob::p_buffer
char * p_buffer
Buffer blob data is stored in.
Definition: Blob.h:93
std
Namespace for the standard library.
Isis::Blob::p_nbytes
int p_nbytes
Size of blob data (in bytes)
Definition: Blob.h:95
Isis::PvlObject::findKeyword
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
Definition: PvlObject.cpp:177
Isis::PvlKeyword::isEquivalent
bool isEquivalent(QString string1, int index=0) const
Checks to see if a value with a specified index is equivalent to another QString.
Definition: PvlKeyword.cpp:562
Isis::Blob
Definition: Blob.h:51
Isis::Blob::p_blobName
QString p_blobName
Name of the Blob object.
Definition: Blob.h:91
Isis::FileName::path
QString path() const
Returns the path of the file name.
Definition: FileName.cpp:103
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16