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
20using namespace std;
21namespace 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
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;
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
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
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];
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
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 != "") {
538 }
539 }
540
547 return p_buffer;
548 }
549
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
PvlObject p_blobPvl
Pvl Blob object.
Definition Blob.h:90
int Size() const
Accessor method that returns the number of bytes in the blob data.
Definition Blob.cpp:142
void setData(const char *buffer, int nbytes)
Set the data stored in the BLOB.
Definition Blob.cpp:382
void Read(const QString &file, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >())
This method reads Pvl values from a specified file.
Definition Blob.cpp:255
QString p_labelFile
The file containing the labels.
Definition Blob.h:98
void Write(const QString &file)
Write the blob data out to a file.
Definition Blob.cpp:417
QString Type() const
Accessor method that returns a string containing the Blob type.
Definition Blob.cpp:124
void Find(const Pvl &pvl, const std::vector< PvlKeyword > keywords=std::vector< PvlKeyword >())
This method searches the given Pvl for the Blob by the Blob's type and name.
Definition Blob.cpp:167
BigInt p_startByte
Byte blob data starts at in buffer.
Definition Blob.h:94
virtual void WriteInit()
This virtual method for classes that inherit Blob.
Definition Blob.cpp:554
virtual void ReadInit()
This virtual method for classes that inherit Blob.
Definition Blob.cpp:341
QString Name() const
Accessor method that returns a string containing the Blob name.
Definition Blob.cpp:133
char * getBuffer()
Get the internal data buff of the Blob.
Definition Blob.cpp:546
virtual void WriteData(std::fstream &os)
Writes blob data to a stream.
Definition Blob.cpp:564
PvlObject & Label()
Accessor method that returns a PvlObject containing the Blob label.
Definition Blob.cpp:151
QString p_type
Type of data stored in the buffer.
Definition Blob.h:96
QString p_detached
Used for reading detached blobs.
Definition Blob.h:97
int p_nbytes
Size of blob data (in bytes)
Definition Blob.h:95
void takeData(char *buffer, int nbytes)
Set the data stored in the BLOB without copying it.
Definition Blob.cpp:398
Blob & operator=(const Blob &other)
This makes the two blob objects exactly the same (copies the blob)
Definition Blob.cpp:92
virtual ~Blob()
Destroys the Blob object.
Definition Blob.cpp:115
char * p_buffer
Buffer blob data is stored in.
Definition Blob.h:93
virtual void ReadData(std::istream &is)
Read binary data from an input stream into the Blob object.
Definition Blob.cpp:351
QString p_blobName
Name of the Blob object.
Definition Blob.h:91
File name manipulation and expansion.
Definition FileName.h:100
QString path() const
Returns the path of the file name.
Definition FileName.cpp:103
QString expanded() const
Returns a QString of the full file name including the file path, excluding the attributes.
Definition FileName.cpp:196
Isis exception class.
Definition IException.h:91
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition IException.h:118
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition IException.h:146
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition IException.h:155
void setName(const QString &name)
Set the name of the container.
QString name() const
Returns the container name.
void deleteKeyword(const QString &name)
Remove a specified keyword.
Container for cube-like labels.
Definition Pvl.h:119
void read(const QString &file)
Loads PVL information from a stream.
Definition Pvl.cpp:90
A single keyword-value pair.
Definition PvlKeyword.h:87
Contains Pvl Groups and Pvl Objects.
Definition PvlObject.h:61
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 ...
PvlObject & object(const int index)
Return the object at the specified index.
void addObject(const PvlObject &object)
Add a PvlObject.
Definition PvlObject.h:309
QString FileOpen(const QString &filename)
This error should be used when a file could not be opened.
Definition FileOpen.cpp:11
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition IString.cpp:211
bool IsBlob(PvlObject &obj)
Checks pvl object and returns whether or not it is a Blob.
Definition Blob.cpp:580
long long int BigInt
Big int.
Definition Constants.h:49
Namespace for the standard library.