storage_bin.cpp

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 //#define DEBUG_PRINT(stream) err << stream
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 //  return err_num != QFile::NoError;
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,             // 1
00156     BT_CHAR,               // 2
00157     BT_SIGNED_CHAR,        // 3
00158     BT_UNSIGNED_CHAR,      // 4
00159     BT_SHORT,              // 5
00160     BT_UNSIGNED_SHORT,     // 6
00161     BT_INT,                // 7
00162     BT_UNSIGNED_INT,       // 8
00163     BT_LONG,               // 9
00164     BT_UNSIGNED_LONG,      // 10
00165     BT_LONG_LONG,          // 11
00166     BT_UNSIGNED_LONG_LONG, // 12
00167     BT_FLOAT,              // 13
00168     BT_DOUBLE,             // 14
00169     BT_LONG_DOUBLE,        // 15
00170     BT_STRING,             // 16
00171     BT_START_REFERENCE,    // 17
00172     BT_START_COMPOUND      // 18
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     // Now write the size of the number types
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)); // Prevent replacing the top-level
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++; // Add one invisible element
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, ""); // Mark of an end of compound
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, ""); // Mark end of reference too
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       // Read type conversion
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     // Read type conversion
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)); // Prevent from using the top-level frame
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++; // Add an unnamed stack
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()) // Skipping an end of compound/reference
00953       return true;
00954     int type = nextElementType();
00955     DEBUG_PRINT("Skipping element " << name << " of type " << type);
00956     elementUsed();
00957     if(type < BT_STRING) // Before string is the sized-size values
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); // Should never happen, but who knows!
00965     }
00966     else if(type == BT_STRING)
00967     {
00968       qint32 size;
00969       file->read((char*)&size, sizeof(qint32));
00970       file->read(size); // Throw the data away
00971     }
00972     else // Compound element
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Fri May 31 15:37:52 2013 for VVE by  doxygen 1.6.3