00001 #include <storage/storage_bin.h>
00002 #include <model.h>
00003
00004 #include <QFile>
00005 #include <QTextStream>
00006 #include <string>
00007
00008 static QTextStream err(stderr);
00009
00010
00011 #define DEBUG_PRINT(stream) void(0)
00012
00013 template <size_t s, typename T>
00014 static T swap_endian(const T& value)
00015 {
00016 T result;
00017 const char* pv = (const char*)&value;
00018 pv += s-1;
00019 char* pr = (char*)&result;
00020 for(size_t i = 0 ; i < s ; ++i)
00021 {
00022 *pr++ = *pv--;
00023 }
00024 return result;
00025 }
00026
00027 #if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
00028 # ifdef WIN32
00029 # define LITTLE_ENDIAN 1234
00030 # define BIG_ENDIAN 4321
00031 # define BYTE_ORDER 1234
00032 # elif __APPLE__
00033 # include <machine/endian.h>
00034 # else
00035 # include <endian.h>
00036 # endif
00037 #endif
00038
00039 #if LITTLE_ENDIAN == BYTE_ORDER
00040 # define little_endian(x) (x)
00041 #elif BIG_ENDIAN == BYTE_ORDER
00042 # define little_endian(x) swap_endian<sizeof(x)>(x)
00043 #else
00044 # error Cannot handle this byte ordering
00045 #endif // LITTLE_ENDIAN
00046
00047 template <typename T>
00048 bool write(QFile* file, const T& data)
00049 {
00050 if(file->write((const char*)&data, sizeof(T)) != sizeof(T))
00051 return false;
00052 QFile::FileError err_num = file->error();
00053
00054 if(err_num != QFile::NoError)
00055 {
00056 DEBUG_PRINT("File error " << err_num << ": " << file->errorString() << endl);
00057 return false;
00058 }
00059 return true;
00060 }
00061
00062 template <typename T>
00063 bool read(QFile* file, T& data)
00064 {
00065 file->read((char*)&data, sizeof(T));
00066 return file->error() != QFile::NoError;
00067 }
00068
00069 bool write(QFile* file, const bool& data)
00070 {
00071 if(data)
00072 file->putChar(1);
00073 else
00074 file->putChar(0);
00075 return file->error() != QFile::NoError;
00076 }
00077
00078 bool read(QFile* file, bool& data)
00079 {
00080 char c;
00081 bool result = file->getChar(&c);
00082 data = (c != 0);
00083 return result;
00084 }
00085
00086 bool write_id(QFile* file, const QString& data)
00087 {
00088 unsigned char size = (unsigned char)data.size();
00089 file->write((const char*)&size, 1);
00090 if(size>0)
00091 {
00092 QByteArray ba = data.toUtf8();
00093 const char* c_data = ba.data();
00094 file->write(c_data, size);
00095 }
00096 return file->error() != QFile::NoError;
00097 }
00098
00099 bool read_id(QFile* file, QString& data)
00100 {
00101 unsigned char size;
00102 file->read((char*)&size, 1);
00103 if(size > 0)
00104 data = QString::fromUtf8(file->read(size));
00105 else
00106 data.clear();
00107 return file->error() != QFile::NoError;
00108 }
00109
00110 bool write(QFile* file, const QString& data)
00111 {
00112 qint32 size = data.size();
00113 file->write((const char*)&size, sizeof(qint32));
00114 if(size>0)
00115 {
00116 QByteArray d = data.toUtf8();
00117 const char* c_data = d.data();
00118 file->write(c_data, size);
00119 }
00120 return file->error() != QFile::NoError;
00121 }
00122
00123 bool read(QFile* file, QString& data)
00124 {
00125 qint32 size;
00126 file->read((char*)&size, sizeof(qint32));
00127 if(size > 0)
00128 data = QString::fromUtf8(file->read(size));
00129 return file->error() != QFile::NoError;
00130 }
00131
00132 bool write(QFile* file, const std::string& data)
00133 {
00134 qint32 size = (int)data.size();
00135 file->write((const char*)&size, sizeof(qint32));
00136 if(size > 0)
00137 file->write(data.c_str(), size);
00138 return file->error() != QFile::NoError;
00139 }
00140
00141 bool read(QFile* file, std::string& data)
00142 {
00143 qint32 size;
00144 file->read((char*)&size, sizeof(qint32));
00145 if(size > 0)
00146 data = QString::fromUtf8(file->read(size)).toStdString();
00147 return file->error() != QFile::NoError;
00148 }
00149
00150 namespace storage
00151 {
00152 enum BIN_TYPES
00153 {
00154 BT_BOOL = 0,
00155 BT_WCHART,
00156 BT_CHAR,
00157 BT_SIGNED_CHAR,
00158 BT_UNSIGNED_CHAR,
00159 BT_SHORT,
00160 BT_UNSIGNED_SHORT,
00161 BT_INT,
00162 BT_UNSIGNED_INT,
00163 BT_LONG,
00164 BT_UNSIGNED_LONG,
00165 BT_LONG_LONG,
00166 BT_UNSIGNED_LONG_LONG,
00167 BT_FLOAT,
00168 BT_DOUBLE,
00169 BT_LONG_DOUBLE,
00170 BT_STRING,
00171 BT_START_REFERENCE,
00172 BT_START_COMPOUND
00173 };
00174
00175 VVEStorage_BINWriter::VVEStorage_BINWriter()
00176 : file(0)
00177 {}
00178
00179 bool VVEStorage_BINWriter::checkFileStatus()
00180 {
00181 if(file->error() != QFile::NoError)
00182 {
00183 setLastError(IO_ERROR, "Error while writing file");
00184 return false;
00185 }
00186 return true;
00187 }
00188
00189 bool VVEStorage_BINWriter::serialize(const QString& filename, Model* model)
00190 {
00191 last_error = NO__ERROR;
00192 last_error_string = QString();
00193
00194 QFile _file(filename);
00195 file = &_file;
00196 references.clear();
00197 if(!file->open(QIODevice::WriteOnly))
00198 {
00199 DEBUG_PRINT("error: " << file->error() << ": " << file->errorString() << endl);
00200 setLastError(IO_ERROR, QString("Could not open file '%1' for writing").arg(filename));
00201 return false;
00202 }
00203 file->write("VVE BIN2\n");
00204
00205 file_version = model->version();
00206
00207 write(file, file_version);
00208
00209 file_version = QString("%1 BIN").arg(file_version);
00210 version_number = model->versionNumber(file_version);
00211
00212
00213 #define WRITE_TYPE_SIZE(id, T) \
00214 write(file, (unsigned char)id); \
00215 write(file, (unsigned char)TypeTraits<T>::type); \
00216 write(file, (unsigned char)sizeof(T));
00217
00218 FOR_ALL_TYPEIDS(WRITE_TYPE_SIZE)
00219
00220 #undef WRITE_TYPE_SIZE
00221
00222 write(file, (unsigned char)T_INVALID);
00223
00224 if(!checkFileStatus()) return false;
00225
00226 frame_stack.push(Frame(0,true));
00227 bool result = model->serialize(*this);
00228 file->close();
00229 if(result)
00230 {
00231 if(frame_stack.empty())
00232 {
00233 setLastError(USER_ERROR, "One too many compound have been closed.");
00234 return false;
00235 }
00236 frame_stack.pop();
00237 if(!frame_stack.empty())
00238 {
00239 setLastError(USER_ERROR, QString("%1 compounds have been opened and not closed.").arg(frame_stack.size()));
00240 return false;
00241 }
00242 }
00243 file = 0;
00244 return result;
00245 }
00246
00247 bool VVEStorage_BINWriter::createElement(const QString& name, unsigned char type)
00248 {
00249 DEBUG_PRINT("Creating element named " << name << endl);
00250 if(!resolveFrame(!name.isEmpty()))
00251 return false;
00252 if(!name.isEmpty())
00253 {
00254 write_id(file, name);
00255 }
00256 write(file, type);
00257 return checkFileStatus();
00258 }
00259
00260 bool VVEStorage_BINWriter::resolveFrame(bool named_field)
00261 {
00262 if(named_field)
00263 {
00264 if(frame_stack.empty())
00265 return true;
00266 DEBUG_PRINT("Resolving compound for named field" << endl);
00267 if(!frame_stack.top().has_fields)
00268 {
00269 DEBUG_PRINT(" -> resolution involves creating the compound" << endl);
00270 unsigned char type = BT_START_COMPOUND;
00271 write(file, type);
00272 frame_stack.top().has_fields = true;
00273 return checkFileStatus();
00274 }
00275 }
00276 else
00277 {
00278 if(frame_stack.empty())
00279 {
00280 setLastError(USER_ERROR, "Cannot create an unnamed field outside any compound.");
00281 return false;
00282 }
00283 if(frame_stack.top().has_fields)
00284 {
00285 setLastError(USER_ERROR, "Cannot use unnamed field on a compound with other fields.");
00286 return false;
00287 }
00288 DEBUG_PRINT("Resolving compound for unnamed field" << endl);
00289 int nb_sub = frame_stack.top().unnamed_subframes;
00290 DEBUG_PRINT(" Number of current unnamed frame on stack: " << frame_stack.top().unnamed_subframes << endl);
00291 frame_stack.pop();
00292 frame_stack.top().unnamed_subframes += nb_sub + 1;
00293 DEBUG_PRINT(" Number of current unnamed frame on stack: " << frame_stack.top().unnamed_subframes << endl);
00294 }
00295 return true;
00296 }
00297
00298 bool VVEStorage_BINWriter::startCompound(const QString& name)
00299 {
00300 if(!name.isEmpty())
00301 {
00302 DEBUG_PRINT("Starting compounds " << name << endl);
00303 if(!resolveFrame())
00304 return false;
00305 write_id(file, name);
00306 frame_stack.push(Frame());
00307 return checkFileStatus();
00308 }
00309 else
00310 {
00311 DEBUG_PRINT("Starting unnamed compounds " << endl);
00312 frame_stack.top().unnamed_subframes++;
00313 }
00314 return true;
00315 }
00316
00317 bool VVEStorage_BINWriter::endCompound()
00318 {
00319 if(frame_stack.empty())
00320 {
00321 setLastError(USER_ERROR, "Error, trying to finish a compound that didn't start");
00322 return false;
00323 }
00324 if(frame_stack.top().unnamed_subframes > 0)
00325 {
00326 DEBUG_PRINT("Ending unnamed compound" << endl);
00327 frame_stack.top().unnamed_subframes--;
00328 DEBUG_PRINT(" unnamed compounds left: " << frame_stack.top().unnamed_subframes << endl);
00329 return true;
00330 }
00331 if(!frame_stack.top().has_fields)
00332 {
00333 unsigned char type = BT_START_COMPOUND;
00334 write(file, type);
00335 if(!checkFileStatus()) return false;
00336 }
00337 DEBUG_PRINT("Ending named compound" << endl);
00338 frame_stack.pop();
00339 write_id(file, "");
00340 return true;
00341 }
00342
00343 int VVEStorage_BINWriter::startReference(const QString& name, const QString& ref_type, reference_t ref)
00344 {
00345 DEBUG_PRINT("Creating reference named " << name << endl);
00346 ref_t& ref_map = references[ref_type];
00347
00348 if(!createElement(name, BT_START_REFERENCE))
00349 return false;
00350
00351 ref_t::iterator found = ref_map.find(ref);
00352 int id = -1;
00353 if(found == ref_map.end())
00354 {
00355 id = (int)ref_map.size();
00356 ref_map[ref] = id;
00357 }
00358 else
00359 {
00360 id = found->second;
00361 }
00362 write(file, (qint32)id);
00363 return id;
00364 }
00365
00366 bool VVEStorage_BINWriter::endReference()
00367 {
00368 DEBUG_PRINT("Ending reference" << endl);
00369 write_id(file, "");
00370 return true;
00371 }
00372
00373 template <typename T>
00374 bool VVEStorage_BINWriter::writeField(const QString& name, T& value)
00375 {
00376 if(!createElement(name, type_id(value)))
00377 return false;
00378 if(type_id(value) != T_STRING)
00379 write(file, little_endian(value));
00380 else
00381 write(file, value);
00382 if(!checkFileStatus()) return false;
00383 return true;
00384 }
00385
00386 #define DEFINES_FIELD_FCT(T) \
00387 bool VVEStorage_BINWriter::field(const QString& name, T& value) \
00388 { \
00389 return writeField(name, value); \
00390 }
00391
00392 FOR_ALL_TYPES(DEFINES_FIELD_FCT)
00393
00394 #undef DEFINES_FIELD_FCT
00395
00396 VVEStorage_BINReader::VVEStorage_BINReader()
00397 : file(0)
00398 , type_check(TCO_Permissive)
00399 {}
00400
00401 bool VVEStorage_BINReader::setOption(int option, int value)
00402 {
00403 switch(option)
00404 {
00405 case TypeChecking:
00406 switch(value)
00407 {
00408 case TCO_Exact:
00409 case TCO_Strict:
00410 case TCO_Permissive:
00411 case TCO_PermissiveNoWarning:
00412 case TCO_NoCheck:
00413 type_check = value;
00414 return true;
00415 default:
00416 return false;
00417 }
00418 break;
00419 default:
00420 return false;
00421 }
00422 }
00423
00424 TYPES read_type(QFile* file)
00425 {
00426 unsigned char t;
00427 read(file, t);
00428 if(t < T_BOOL or t > T_STRING)
00429 return T_INVALID;
00430 return (TYPES)t;
00431 }
00432
00433 namespace old
00434 {
00439 class VVEStorage_BINReader : public VVEStorage
00440 {
00441 public:
00443 typedef ptrdiff_t reference_t;
00444
00445 VVEStorage_BINReader();
00446 virtual ~VVEStorage_BINReader() {}
00447
00448 virtual bool setOption(int option, int value);
00449
00453 virtual bool serialize(const QString& filename, Model* model);
00454
00455 virtual bool startCompound(const QString& name);
00456 virtual bool endCompound();
00457
00458 virtual int startReference(const QString& name, const QString& ref_type, reference_t ref);
00459 virtual bool endReference();
00460
00461 virtual bool reader() { return true; }
00462 virtual bool writer() { return false; }
00463
00464 #define DEF_FIELD(T) virtual bool field(const QString& name, T& value);
00465 FOR_ALL_TYPES(DEF_FIELD)
00466 #undef DEF_FIELD
00467
00468 bool checkNextField(const QString& name);
00469 virtual void setLastError(int error, const QString& err);
00470
00474 virtual QString filename() const
00475 {
00476 if(file)
00477 return file->fileName();
00478 else
00479 return "";
00480 }
00481
00482 protected:
00483 unsigned char nextElementType();
00484 const QString& nextElementName();
00485 bool checkFileStatus();
00486
00487 template <typename Read, typename Store>
00488 bool readData(QFile* file, Store& value);
00489
00490 template <typename T>
00491 bool readValue(const QString& name, T& value);
00492
00493 QFile *file;
00494 int type_check;
00495
00496 void elementUsed();
00497
00498 QString next_element_name;
00499 bool has_next_element_name;
00500
00501 TYPES type_conversion[NB_STORAGE_TYPES];
00502 size_t type_size[NB_STORAGE_TYPES];
00503 NUMBER_CLASS type_class[NB_STORAGE_TYPES];
00504 };
00505
00506 VVEStorage_BINReader::VVEStorage_BINReader()
00507 : file(0)
00508 , type_check(TCO_Permissive)
00509 {}
00510
00511 bool VVEStorage_BINReader::setOption(int option, int value)
00512 {
00513 switch(option)
00514 {
00515 case TypeChecking:
00516 switch(value)
00517 {
00518 case TCO_Exact:
00519 case TCO_Strict:
00520 case TCO_Permissive:
00521 case TCO_PermissiveNoWarning:
00522 case TCO_NoCheck:
00523 type_check = value;
00524 return true;
00525 default:
00526 return false;
00527 }
00528 break;
00529 default:
00530 return false;
00531 }
00532 }
00533
00534
00535 bool VVEStorage_BINReader::serialize(const QString& filename, Model* model)
00536 {
00537 last_error = NO__ERROR;
00538 last_error_string = QString();
00539
00540 QFile _file(filename);
00541 file = &_file;
00542 has_next_element_name = false;
00543 references.clear();
00544 if(!file->open(QIODevice::ReadOnly))
00545 {
00546 setLastError(IO_ERROR, QString("Could not open file '%1' for reading").arg(filename));
00547 return false;
00548 }
00549 QByteArray first_line = file->readLine();
00550 if(first_line != "VVE BIN\n")
00551 {
00552 setLastError(BAD_CONTENT, QString("File '%1' is not a VVE BIN file").arg(filename));
00553 return false;
00554 }
00555
00556 read(file, file_version);
00557 file_version = QString("%1 BIN").arg(file_version);
00558 version_number = model->versionNumber(file_version);
00559
00560 if(!checkFileStatus()) return false;
00561
00562
00563 TYPES type;
00564 while((type = read_type(file)) != T_INVALID)
00565 {
00566 unsigned char t;
00567 unsigned char s;
00568 read(file, t);
00569 read(file, s);
00570 NUMBER_CLASS k = (NUMBER_CLASS)t;
00571 size_t size = (size_t)s;
00572 type_conversion[type] = find_type(k, size);
00573 type_size[type] = size;
00574 type_class[type] = k;
00575 }
00576
00577 type_conversion[T_STRING] = T_STRING;
00578 type_conversion[T_BOOL] = T_BOOL;
00579
00580 bool result = model->serialize(*this);
00581 file->close();
00582 file = 0;
00583 return result;
00584 }
00585
00586 void VVEStorage_BINReader::elementUsed()
00587 {
00588 has_next_element_name = false;
00589 }
00590
00591 unsigned char VVEStorage_BINReader::nextElementType()
00592 {
00593 unsigned char type;
00594 read(file, type);
00595 return type;
00596 }
00597
00598 bool VVEStorage_BINReader::startCompound(const QString& name)
00599 {
00600 if(name.isEmpty())
00601 return true;
00602 const QString& next_name = nextElementName();
00603 if(next_name != name)
00604 {
00605 setLastError(BAD_CONTENT, QString("Next compound has name '%1' instead of the expected '%2'").arg(next_name, name));
00606 return false;
00607 }
00608 elementUsed();
00609 return true;
00610 }
00611
00612 bool VVEStorage_BINReader::endCompound()
00613 {
00614 return true;
00615 }
00616
00617 bool VVEStorage_BINReader::checkFileStatus()
00618 {
00619 if(file->error() != QFile::NoError)
00620 {
00621 setLastError(IO_ERROR, "Error while reading file");
00622 return false;
00623 }
00624 return true;
00625 }
00626
00627 int VVEStorage_BINReader::startReference(const QString& name, const QString&, reference_t)
00628 {
00629 if(!name.isEmpty())
00630 {
00631 const QString& next_name = nextElementName();
00632 if(next_name != name)
00633 {
00634 setLastError(BAD_CONTENT, QString("Error, expected reference named '%1' but found element named '%2'").arg(name, next_name));
00635 return -1;
00636 }
00637 }
00638 unsigned char type = nextElementType();
00639 if(type != BT_START_REFERENCE)
00640 {
00641 setLastError(TYPE_CHECK_ERROR, QString("Element '%1' is not a reference").arg(name));
00642 return -1;
00643 }
00644 qint32 id;
00645 read(file, id);
00646 if(!checkFileStatus()) return false;
00647 elementUsed();
00648 return id;
00649 }
00650
00651 bool VVEStorage_BINReader::endReference()
00652 {
00653 return true;
00654 }
00655
00656 template <typename Read, typename Store>
00657 bool VVEStorage_BINReader::readData(QFile* file, Store& value)
00658 {
00659 Read to_read;
00660 read(file, to_read);
00661 if(!convert_type(to_read, value))
00662 {
00663 setLastError(TYPE_CONVERSION_ERROR, QString("Error, cannot convert value type '%2' to type '%3'").arg(type_name(to_read)).arg(type_name(value)));
00664 return false;
00665 }
00666 if(type_id(value) != T_STRING)
00667 value = little_endian(value);
00668 return checkFileStatus();
00669 }
00670
00671 template <typename T>
00672 bool VVEStorage_BINReader::readValue(const QString& name, T& value)
00673 {
00674 if(!name.isEmpty())
00675 {
00676 const QString& next_name = nextElementName();
00677 if(next_name != name)
00678 {
00679 setLastError(BAD_CONTENT, QString("Next element has name '%1' when name '%2' was expected").arg(next_name, name));
00680 return false;
00681 }
00682 }
00683 int read_type = nextElementType();
00684 if(read_type >= NB_STORAGE_TYPES)
00685 {
00686 setLastError(TYPE_CHECK_ERROR, QString("Type id '%1' does not correspond to a value type").arg(read_type));
00687 return false;
00688 }
00689 int actual_type = type_conversion[read_type];
00690 if(actual_type == T_INVALID)
00691 {
00692 QString tc;
00693 switch(type_class[read_type])
00694 {
00695 case SIGNED_INTEGER:
00696 tc = "signed integer";
00697 break;
00698 case UNSIGNED_INTEGER:
00699 tc = "unsigned integer";
00700 break;
00701 case FLOATING_POINT:
00702 tc = "floating point";
00703 break;
00704 case CHAR:
00705 tc = "char";
00706 break;
00707 case NOT_A_NUMBER:
00708 tc = "NotANumber";
00709 break;
00710 }
00711 setLastError(TYPE_CONVERSION_ERROR, QString("Your system does not support %1 type on %2 bytes.").arg(tc).arg(type_size[read_type]));
00712 return false;
00713 }
00714 int type = type_id(value);
00715 elementUsed();
00716 switch(type_check)
00717 {
00718 case TCO_Strict:
00719 if(type != actual_type)
00720 {
00721 setLastError(TYPE_CHECK_ERROR, QString("Expected type %1 but read type %2.").arg(type_name(value)).arg(typeid_to_name((TYPES)actual_type)));
00722 return false;
00723 }
00724 read(file, value);
00725 if(type_id(value) != T_STRING)
00726 value = little_endian(value);
00727 return true;
00728 case TCO_Permissive:
00729 if(!isStrictConversion((TYPES)actual_type, (TYPES)type))
00730 {
00731 DEBUG_PRINT("Warning: Conversion from type " << typeid_to_name((TYPES)actual_type) << " to " << typeid_to_name((TYPES)type) << " can lead to loss of precision" << endl);
00732 }
00733 case TCO_PermissiveNoWarning:
00734 case TCO_NoCheck:
00735 switch(actual_type)
00736 {
00737 #define CONVERT_TYPE(type_id, ToRead) \
00738 case type_id: \
00739 return readData<ToRead,T>(file, value);
00740
00741 FOR_ALL_TYPEIDS(CONVERT_TYPE)
00742 #undef CONVERT_TYPE
00743 default:
00744 setLastError(TYPE_CHECK_ERROR, QString("Unknown type id '%1'").arg(actual_type));
00745 return false;
00746 }
00747 default:
00748 setLastError(BAD_CONTENT, QString("Unknown type check method %1").arg(type_check));
00749 return false;
00750 }
00751 }
00752
00753 #define DEFINES_FIELD_FCT(T) \
00754 bool VVEStorage_BINReader::field(const QString& name, T& value) \
00755 { \
00756 return readValue(name, value); \
00757 }
00758
00759 FOR_ALL_TYPES(DEFINES_FIELD_FCT)
00760 #undef DEFINES_FIELD_FCT
00761
00762 const QString& VVEStorage_BINReader::nextElementName()
00763 {
00764 if(has_next_element_name)
00765 return next_element_name;
00766 read_id(file, next_element_name);
00767 has_next_element_name = true;
00768 return next_element_name;
00769 }
00770
00771 bool VVEStorage_BINReader::checkNextField(const QString& name)
00772 {
00773 const QString& next_name = nextElementName();
00774 return next_name == name;
00775 }
00776
00777 void VVEStorage_BINReader::setLastError(int error, const QString& err)
00778 {
00779 last_error = error;
00780 last_error_string = QString("Error at position %1 of the file:\n%2").arg(file->pos()).arg(err);
00781 }
00782
00783 };
00784
00785 bool VVEStorage_BINReader::serialize(const QString& filename, Model* model)
00786 {
00787 last_error = NO__ERROR;
00788 last_error_string = QString();
00789
00790 QFile _file(filename);
00791 file = &_file;
00792 has_next_element_name = false;
00793 references.clear();
00794 if(!file->open(QIODevice::ReadOnly))
00795 {
00796 setLastError(IO_ERROR, QString("Could not open file '%1' for reading").arg(filename));
00797 return false;
00798 }
00799 QByteArray first_line = file->readLine();
00800 if(first_line == "VVE BIN\n")
00801 {
00802 _file.close();
00803 old::VVEStorage_BINReader reader;
00804 return reader.serialize(filename, model);
00805 }
00806 if(first_line != "VVE BIN2\n")
00807 {
00808 setLastError(BAD_CONTENT, QString("File '%1' is not a VVE BIN file").arg(filename));
00809 return false;
00810 }
00811 DEBUG_PRINT("Starting reader for BIN2" << endl);
00812
00813 read(file, file_version);
00814 file_version = QString("%1 BIN").arg(file_version);
00815 version_number = model->versionNumber(file_version);
00816
00817 if(!checkFileStatus()) return false;
00818
00819
00820 TYPES type;
00821 while((type = read_type(file)) != T_INVALID)
00822 {
00823 unsigned char t;
00824 unsigned char s;
00825 read(file, t);
00826 read(file, s);
00827 NUMBER_CLASS k = (NUMBER_CLASS)t;
00828 size_t size = (size_t)s;
00829 type_conversion[type] = find_type(k, size);
00830 type_size[type] = size;
00831 type_class[type] = k;
00832 }
00833
00834 type_conversion[T_STRING] = T_STRING;
00835 type_conversion[T_BOOL] = T_BOOL;
00836
00837 frame_stack.push(Frame(0,true));
00838 bool result = model->serialize(*this);
00839 file->close();
00840 if(result)
00841 {
00842 if(frame_stack.empty())
00843 {
00844 setLastError(USER_ERROR, "One too many compound have been closed.");
00845 return false;
00846 }
00847 frame_stack.pop();
00848 if(!frame_stack.empty())
00849 {
00850 setLastError(USER_ERROR, QString("%1 compounds have been opened and not closed.").arg(frame_stack.size()));
00851 return false;
00852 }
00853 }
00854 file = 0;
00855 return result;
00856 }
00857
00858 void VVEStorage_BINReader::elementUsed()
00859 {
00860 has_next_element_name = false;
00861 }
00862
00863 unsigned char VVEStorage_BINReader::nextElementType()
00864 {
00865 unsigned char type;
00866 read(file, type);
00867 return type;
00868 }
00869
00870 bool VVEStorage_BINReader::resolveFrame(bool named_field)
00871 {
00872 DEBUG_PRINT("Resolving compound" << endl);
00873 if(named_field)
00874 {
00875 if(frame_stack.empty())
00876 {
00877 DEBUG_PRINT(" nothing to do ... " << endl);
00878 return true;
00879 }
00880 if(!frame_stack.top().has_fields)
00881 {
00882 DEBUG_PRINT(" Finalizing compound" << endl);
00883 if(nextElementType() != BT_START_COMPOUND)
00884 {
00885 setLastError(BAD_CONTENT, "Current element is not a compound when it should be.");
00886 return false;
00887 }
00888 frame_stack.top().has_fields = true;
00889 }
00890 else
00891 {
00892 DEBUG_PRINT(" nothing to do ... " << endl);
00893 }
00894 }
00895 else
00896 {
00897 if(frame_stack.empty())
00898 {
00899 setLastError(USER_ERROR, "Cannot have an unnamed field outside any compound");
00900 return false;
00901 }
00902 if(frame_stack.top().has_fields)
00903 {
00904 setLastError(USER_ERROR, "Trying to read an unnamed field in a compound with other fields.");
00905 return false;
00906 }
00907 int nb_frames = frame_stack.top().unnamed_subframes;
00908 frame_stack.pop();
00909 frame_stack.top().unnamed_subframes += nb_frames+1;
00910 DEBUG_PRINT(" .. merging compounds: number of unnamed frames = " << frame_stack.top().unnamed_subframes << endl);
00911 DEBUG_PRINT(" had fields = " << frame_stack.top().has_fields << endl);
00912 }
00913 return true;
00914 }
00915
00916 bool VVEStorage_BINReader::startCompound(const QString& name)
00917 {
00918 if(name.isEmpty())
00919 {
00920 DEBUG_PRINT("Start unnamed compound " << endl);
00921 frame_stack.top().unnamed_subframes++;
00922 return true;
00923 }
00924 if(!resolveFrame())
00925 return false;
00926 DEBUG_PRINT("Start compound " << name << " on pos " << file->pos () << endl);
00927 const QString& next_name = nextElementName();
00928 if(next_name != name)
00929 {
00930 setLastError(BAD_CONTENT, QString("Next compound has name '%1' instead of the expected '%2'").arg(next_name, name));
00931 return false;
00932 }
00933 elementUsed();
00934 frame_stack.push(Frame());
00935 return true;
00936 }
00937
00938 bool VVEStorage_BINReader::ignore(const QString& name)
00939 {
00940 const QString& next_name = nextElementName();
00941 if(next_name != name)
00942 {
00943 setLastError(BAD_CONTENT, QString("Trying skip element %1 when the next element is %2").arg(name).arg(next_name));
00944 return false;
00945 }
00946 return skipNext();
00947 }
00948
00949 bool VVEStorage_BINReader::skipNext()
00950 {
00951 QString name = nextElementName();
00952 if(nextElementName().isEmpty())
00953 return true;
00954 int type = nextElementType();
00955 DEBUG_PRINT("Skipping element " << name << " of type " << type);
00956 elementUsed();
00957 if(type < BT_STRING)
00958 {
00959 int size = (int)type_size[type];
00960 static char buffer[100];
00961 if(size < 100)
00962 file->read(buffer, size);
00963 else
00964 file->read(size);
00965 }
00966 else if(type == BT_STRING)
00967 {
00968 qint32 size;
00969 file->read((char*)&size, sizeof(qint32));
00970 file->read(size);
00971 }
00972 else
00973 {
00974 if(type == BT_START_REFERENCE)
00975 {
00976 qint32 id;
00977 read(file, id);
00978 }
00979 QString name = nextElementName();
00980 while(!name.isEmpty())
00981 {
00982 if(!skipNext())
00983 return false;
00984 name = nextElementName();
00985 }
00986 elementUsed();
00987 }
00988 return checkFileStatus();
00989 }
00990
00991 bool VVEStorage_BINReader::skipToEnd()
00992 {
00993 while(!nextElementName().isEmpty())
00994 {
00995 if(!skipNext())
00996 return false;
00997 }
00998 elementUsed();
00999 return checkFileStatus();
01000 }
01001
01002 bool VVEStorage_BINReader::endCompound()
01003 {
01004 if(frame_stack.empty())
01005 {
01006 setLastError(USER_ERROR, "Trying to close a compound that wasn't opened");
01007 return false;
01008 }
01009 if(frame_stack.top().unnamed_subframes > 0)
01010 {
01011 DEBUG_PRINT("Ending unnamed compound" << endl);
01012 frame_stack.top().unnamed_subframes--;
01013 return true;
01014 }
01015 DEBUG_PRINT("Ending named compound" << endl);
01016 frame_stack.pop();
01017 return skipToEnd();
01018 }
01019
01020 bool VVEStorage_BINReader::checkFileStatus()
01021 {
01022 if(file->error() != QFile::NoError)
01023 {
01024 setLastError(IO_ERROR, "Error while reading file");
01025 return false;
01026 }
01027 return true;
01028 }
01029
01030 int VVEStorage_BINReader::startReference(const QString& name, const QString&, reference_t)
01031 {
01032 if(!resolveFrame(!name.isEmpty()))
01033 return false;
01034 if(!name.isEmpty())
01035 {
01036 DEBUG_PRINT("Starting reference named " << name << endl);
01037 const QString& next_name = nextElementName();
01038 if(next_name != name)
01039 {
01040 setLastError(BAD_CONTENT, QString("Error, expected reference named '%1' but found element named '%2'").arg(name, next_name));
01041 return -1;
01042 }
01043 }
01044 else
01045 {
01046 DEBUG_PRINT("Starting unnamed reference" << endl);
01047 }
01048 unsigned char type = nextElementType();
01049 if(type != BT_START_REFERENCE)
01050 {
01051 setLastError(TYPE_CHECK_ERROR, QString("Element '%1' is not a reference").arg(name));
01052 return -1;
01053 }
01054 qint32 id;
01055 read(file, id);
01056 if(!checkFileStatus()) return false;
01057 elementUsed();
01058 return id;
01059 }
01060
01061 bool VVEStorage_BINReader::endReference()
01062 {
01063 DEBUG_PRINT("End of reference" << endl);
01064 return skipToEnd();
01065 }
01066
01067 template <typename Read, typename Store>
01068 bool VVEStorage_BINReader::readData(QFile* file, Store& value)
01069 {
01070 Read to_read;
01071 read(file, to_read);
01072 if(!convert_type(to_read, value))
01073 {
01074 setLastError(TYPE_CONVERSION_ERROR, QString("Error, cannot convert value type '%2' to type '%3'").arg(type_name(to_read)).arg(type_name(value)));
01075 return false;
01076 }
01077 if(type_id(value) != T_STRING)
01078 value = little_endian(value);
01079 return checkFileStatus();
01080 }
01081
01082 template <typename T>
01083 bool VVEStorage_BINReader::readValue(const QString& name, T& value)
01084 {
01085 DEBUG_PRINT("Reading field " << name << endl);
01086 if(!resolveFrame(!name.isEmpty()))
01087 {
01088 DEBUG_PRINT("could not resolve compound" << endl);
01089 return false;
01090 }
01091 if(!name.isEmpty())
01092 {
01093 const QString& next_name = nextElementName();
01094 if(next_name != name)
01095 {
01096 DEBUG_PRINT("error on pos " << file->pos() << ": element name was " << next_name << " while " << name << " was expected" << endl);
01097 setLastError(BAD_CONTENT, QString("Next element has name '%1' when name '%2' was expected").arg(next_name, name));
01098 return false;
01099 }
01100 }
01101 int read_type = nextElementType();
01102 DEBUG_PRINT("next element type = " << read_type << endl);
01103 if(read_type >= NB_STORAGE_TYPES)
01104 {
01105 setLastError(TYPE_CHECK_ERROR, QString("Type id '%1' does not correspond to a value type").arg(read_type));
01106 return false;
01107 }
01108 int actual_type = type_conversion[read_type];
01109 DEBUG_PRINT("actual type = " << actual_type << endl);
01110 if(actual_type == T_INVALID)
01111 {
01112 QString tc;
01113 switch(type_class[read_type])
01114 {
01115 case SIGNED_INTEGER:
01116 tc = "signed integer";
01117 break;
01118 case UNSIGNED_INTEGER:
01119 tc = "unsigned integer";
01120 break;
01121 case FLOATING_POINT:
01122 tc = "floating point";
01123 break;
01124 case CHAR:
01125 tc = "char";
01126 break;
01127 case NOT_A_NUMBER:
01128 tc = "NotANumber";
01129 break;
01130 }
01131 setLastError(TYPE_CONVERSION_ERROR, QString("Your system does not support %1 type on %2 bytes.").arg(tc).arg(type_size[read_type]));
01132 return false;
01133 }
01134 int type = type_id(value);
01135 elementUsed();
01136 DEBUG_PRINT(" -> type of value = " << type << endl);
01137 switch(type_check)
01138 {
01139 case TCO_Strict:
01140 if(type != actual_type)
01141 {
01142 setLastError(TYPE_CHECK_ERROR, QString("Expected type %1 but read type %2.").arg(type_name(value)).arg(typeid_to_name((TYPES)actual_type)));
01143 return false;
01144 }
01145 read(file, value);
01146 if(type_id(value) != T_STRING)
01147 value = little_endian(value);
01148 return true;
01149 case TCO_Permissive:
01150 if(!isStrictConversion((TYPES)actual_type, (TYPES)type))
01151 {
01152 DEBUG_PRINT("Warning: Conversion from type " << typeid_to_name((TYPES)actual_type) << " to " << typeid_to_name((TYPES)type) << " can lead to loss of precision" << endl);
01153 }
01154 case TCO_PermissiveNoWarning:
01155 case TCO_NoCheck:
01156 switch(actual_type)
01157 {
01158 #define CONVERT_TYPE(type_id, ToRead) \
01159 case type_id: \
01160 return readData<ToRead,T>(file, value);
01161
01162 FOR_ALL_TYPEIDS(CONVERT_TYPE)
01163 #undef CONVERT_TYPE
01164 default:
01165 setLastError(TYPE_CHECK_ERROR, QString("Unknown type id '%1'").arg(actual_type));
01166 return false;
01167 }
01168 default:
01169 setLastError(BAD_CONTENT, QString("Unknown type check method %1").arg(type_check));
01170 return false;
01171 }
01172 }
01173
01174 #define DEFINES_FIELD_FCT(T) \
01175 bool VVEStorage_BINReader::field(const QString& name, T& value) \
01176 { \
01177 return readValue(name, value); \
01178 }
01179
01180 FOR_ALL_TYPES(DEFINES_FIELD_FCT)
01181 #undef DEFINES_FIELD_FCT
01182
01183 const QString& VVEStorage_BINReader::nextElementName()
01184 {
01185 if(has_next_element_name)
01186 return next_element_name;
01187 DEBUG_PRINT(".. Reading next element type at position " << file->pos() << endl);
01188 read_id(file, next_element_name);
01189 DEBUG_PRINT(".... name is: '" << next_element_name << "'" << endl);
01190 has_next_element_name = true;
01191 return next_element_name;
01192 }
01193
01194 bool VVEStorage_BINReader::checkNextField(const QString& name)
01195 {
01196 resolveFrame();
01197 const QString& next_name = nextElementName();
01198 DEBUG_PRINT("Checking if field " << name << " is the next one: " << (next_name == name) << endl);
01199 return next_name == name;
01200 }
01201
01202 void VVEStorage_BINReader::setLastError(int error, const QString& err)
01203 {
01204 last_error = error;
01205 last_error_string = QString("Error at position %1 of the file:\n%2").arg(file->pos()).arg(err);
01206 }
01207
01208 }