Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #ifndef VLXParserVLB_INCLUDE_ONCE
00033 #define VLXParserVLB_INCLUDE_ONCE
00034
00035 #include <vlCore/VLXParser.hpp>
00036 #include <vlCore/VLXBinaryDefs.hpp>
00037
00038 namespace vl
00039 {
00041 class VLXParserVLB: public VLXParser
00042 {
00043 VL_INSTRUMENT_CLASS(vl::VLXParserVLB, VLXParser)
00044
00045 public:
00046 VLXParserVLB()
00047 {
00048 mVersion = 0;
00049 }
00050
00051 bool parseHeader()
00052 {
00053 mVersion = 0;
00054 mEncoding.clear();
00055 mFlags = 0;
00056
00057
00058 unsigned char vlx_identifier[] = { 0xAB, 'V', 'L', 'X', 0xBB, 0x0D, 0x0A, 0x1A, 0x0A };
00059 unsigned char vlx[sizeof(vlx_identifier)];
00060 memset(vlx, 0, sizeof(vlx));
00061 inputFile()->read(vlx, sizeof(vlx));
00062 if ( memcmp(vlx, vlx_identifier, sizeof(vlx)) != 0 )
00063 return false;
00064
00065 if ( inputFile()->readUInt16(&mVersion,1) != 2 )
00066 return false;
00067
00068 unsigned char ch = 0xFF;
00069 for( ; inputFile()->readUInt8(&ch, 1) && ch ; ch = 0xFF )
00070 mEncoding.push_back(ch);
00071 if (ch)
00072 return false;
00073
00074 if ( inputFile()->readUInt32(&mFlags, 1) != 4 )
00075 return false;
00076
00077 return true;
00078 }
00079
00080 bool readChunk(unsigned char& chunk) { return inputFile()->read(&chunk, 1) == 1; }
00081
00082 bool readInteger(long long& n)
00083 {
00084 #if 0
00085 return inputFile()->read(&n, sizeof(n)) == sizeof(n);
00086 #else
00087 const unsigned char nxt_flag = 0x80;
00088 const unsigned char neg_flag = 0x40;
00089 unsigned char byte = 0;
00090 if ( inputFile()->read(&byte, 1) != 1 )
00091 return false;
00092 bool is_neg = (byte & neg_flag) != 0;
00093 n = byte & 0x3F;
00094 int shift = 6;
00095 while(byte & nxt_flag)
00096 {
00097 if ( inputFile()->read(&byte, 1) != 1 )
00098 return false;
00099 n |= (long long)(byte & 0x7F) << shift;
00100 shift += 7;
00101 }
00102 if (is_neg)
00103 n = -n;
00104 return true;
00105 #endif
00106 }
00107
00108 void decodeIntegers(const std::vector<unsigned char>& in, std::vector<long long>& out)
00109 {
00110 out.reserve(in.size());
00111 const unsigned char nxt_flag = 0x80;
00112 const unsigned char neg_flag = 0x40;
00113 for( size_t i=0 ; i<in.size() ; )
00114 {
00115 unsigned char byte = in[i++];
00116 bool is_neg = (byte & neg_flag) != 0;
00117 long long n = byte & 0x3F;
00118 int shift = 6;
00119 while(byte & nxt_flag)
00120 {
00121 byte = in[i++];
00122 n |= (long long)(byte & 0x7F) << shift;
00123 shift += 7;
00124 }
00125 if (is_neg)
00126 n = -n;
00127
00128 out.push_back(n);
00129 }
00130 }
00131
00132 bool readString(std::string& str)
00133 {
00134 long long len = 0;
00135 if (!readInteger(len))
00136 return false;
00137 VL_CHECK(len >= 0 );
00138 if (len < 0)
00139 return false;
00140 if (len == 0)
00141 return true;
00142 str.resize((size_t)len);
00143 bool ok = (size_t)inputFile()->read(&str[0], str.length()) == str.length();
00144 return ok;
00145 }
00146
00147 bool parse()
00148 {
00149 class CloseFileClass
00150 {
00151 public:
00152 CloseFileClass(VirtualFile* f): mFile(f) {}
00153 ~CloseFileClass()
00154 {
00155 if (mFile)
00156 mFile->close();
00157 }
00158 private:
00159 ref<VirtualFile> mFile;
00160 } CloseFile(inputFile());
00161
00162 inputFile()->close();
00163 inputFile()->open(OM_ReadOnly);
00164
00165
00166 mMetadata.clear();
00167
00168
00169 mVersion = 0;
00170 mEncoding.clear();
00171
00172 if (!parseHeader())
00173 {
00174 Log::error("VLXParserVLB : error parsing VLB header.\n");
00175 return false;
00176 }
00177
00178 if (mVersion != 100)
00179 {
00180 Log::error("VLX version not supported.\n");
00181 return false;
00182 }
00183
00184 if (mEncoding != "ascii")
00185 {
00186 Log::error("Encoding not supported.\n");
00187 return false;
00188 }
00189
00190 unsigned char chunk;
00191 std::string str;
00192
00193 while(readChunk(chunk))
00194 {
00195 if(chunk == VLB_ChunkStructure)
00196 {
00197 ref<VLXStructure> st = new VLXStructure;
00198
00199 if (!parseStructure(st.get()))
00200 {
00201 Log::error( Say("Error parsing binary file at offset %n.\n") << inputFile()->position() );
00202 return false;
00203 }
00204
00205 mStructures.push_back(st);
00206 }
00207 else
00208 {
00209 Log::error( Say("Error parsing binary file at offset %n. Expected chunk structure.\n") << inputFile()->position() );
00210 return false;
00211 }
00212 }
00213
00214 parseMetadata();
00215
00216 return true;
00217 }
00218
00219 bool parseStructure(VLXStructure* st)
00220 {
00221 std::string str;
00222
00223
00224 if (!readString(str))
00225 return false;
00226 st->setTag(str.c_str());
00227
00228
00229 if (!readString(str))
00230 return false;
00231 st->setID(str.c_str());
00232
00233
00234 long long count = 0;
00235 if (!readInteger(count))
00236 return false;
00237
00238
00239 for(int i=0; i<count; ++i)
00240 {
00241 VLXStructure::Value val;
00242
00243
00244 if (!readString(str))
00245 return false;
00246 val.setKey(str.c_str());
00247
00248
00249 if (!readValue(val.value()))
00250 return false;
00251 st->value().push_back(val);
00252 }
00253
00254 return true;
00255 }
00256
00257 bool parseList(VLXList* list)
00258 {
00259 std::string str;
00260
00261
00262 if (!readString(str))
00263 return false;
00264 list->setTag(str.c_str());
00265
00266
00267 long long count = 0;
00268 if (!readInteger(count))
00269 return false;
00270
00271
00272 for(int i=0; i<count; ++i)
00273 {
00274 VLXValue val;
00275
00276 if (!readValue(val))
00277 return false;
00278 else
00279 list->value().push_back(val);
00280 }
00281
00282 return true;
00283 }
00284
00285 bool readValue(VLXValue& val)
00286 {
00287 unsigned char chunk = 0;
00288
00289 if (!readChunk(chunk))
00290 return false;
00291
00292 std::string str;
00293
00294 switch(chunk)
00295 {
00296
00297 case VLB_ChunkStructure:
00298 val.setStructure( new VLXStructure );
00299 return parseStructure( val.getStructure() );
00300
00301 case VLB_ChunkList:
00302 val.setList( new VLXList );
00303 return parseList( val.getList() );
00304
00305 case VLB_ChunkArrayInteger:
00306 {
00307
00308 if (!readString(str))
00309 return false;
00310 else
00311 val.setArrayInteger( new VLXArrayInteger( str.c_str() ) );
00312
00313
00314 long long count = 0;
00315 if (!readInteger(count))
00316 return false;
00317
00318
00319 VLXArrayInteger& arr = *val.getArrayInteger();
00320 if (count)
00321 {
00322 long long encode_count = 0;
00323 if (!readInteger(encode_count))
00324 return false;
00325 VL_CHECK(encode_count >= 0)
00326 if (encode_count)
00327 {
00328 std::vector<unsigned char> encoded;
00329 encoded.resize((size_t)encode_count);
00330 inputFile()->readUInt8(&encoded[0], encode_count);
00331 decodeIntegers(encoded, arr.value());
00332 }
00333 }
00334 VL_CHECK((size_t)count == arr.value().size())
00335 return (size_t)count == arr.value().size();
00336 }
00337
00338 case VLB_ChunkArrayRealDouble:
00339 {
00340
00341 if (!readString(str))
00342 return false;
00343 else
00344 val.setArrayReal( new VLXArrayReal( str.c_str() ) );
00345
00346 long long count = 0;
00347 if (!readInteger(count))
00348 return false;
00349
00350 VLXArrayReal& arr = *val.getArrayReal();
00351 arr.value().resize( (size_t)count );
00352 if (count)
00353 {
00354 #if 1
00355 long long c = inputFile()->readDouble( &arr.value()[0], count );
00356 VL_CHECK(c == count * (int)sizeof(double))
00357 return c == count * (int)sizeof(double);
00358 #elif 0
00359 long long zsize = 0;
00360 readInteger(zsize);
00361 std::vector<unsigned char> zipped;
00362 zipped.resize((size_t)zsize);
00363 inputFile()->read(&zipped[0], zipped.size());
00364 bool ok = decompress(&zipped[0], (size_t)zsize, &arr.value()[0]);
00365 VL_CHECK(ok);
00366 return ok;
00367 #endif
00368 }
00369 else
00370 return true;
00371 }
00372
00373 case VLB_ChunkArrayRealFloat:
00374 {
00375
00376 if (!readString(str))
00377 return false;
00378 else
00379 val.setArrayReal( new VLXArrayReal( str.c_str() ) );
00380
00381 long long count = 0;
00382 if (!readInteger(count))
00383 return false;
00384
00385 VLXArrayReal& arr = *val.getArrayReal();
00386 arr.value().resize( (size_t)count );
00387 if (count)
00388 {
00389 #if 1
00390 std::vector<float> floats;
00391 floats.resize( (size_t)count );
00392 long long c = inputFile()->readFloat( &floats[0], count );
00393
00394 for(size_t i=0; i<floats.size(); ++i)
00395 arr.value()[i] = floats[i];
00396 VL_CHECK(c == count * (int)sizeof(float))
00397 return c == count * (int)sizeof(float);
00398 #elif 0
00399 long long zsize = 0;
00400 readInteger(zsize);
00401 std::vector<unsigned char> zipped;
00402 zipped.resize((size_t)zsize);
00403 inputFile()->read(&zipped[0], zipped.size());
00404 bool ok = decompress(&zipped[0], (size_t)zsize, &arr.value()[0]);
00405 VL_CHECK(ok);
00406 return ok;
00407 #endif
00408 }
00409 else
00410 return true;
00411 }
00412
00413 case VLB_ChunkRawtext:
00414
00415 if (!readString(str))
00416 return false;
00417 else
00418 val.setRawtextBlock( new VLXRawtextBlock( str.c_str() ) );
00419
00420 if (!readString(str))
00421 return false;
00422 else
00423 {
00424 val.getRawtextBlock()->setValue( str.c_str() );
00425 return true;
00426 }
00427
00428 case VLB_ChunkInteger:
00429 {
00430 long long i = 0;
00431 if (!readInteger(i))
00432 return false;
00433 else
00434 {
00435 val.setInteger(i);
00436 return true;
00437 }
00438 }
00439
00440 case VLB_ChunkRealDouble:
00441 {
00442 double d = 0;
00443 if (inputFile()->readDouble(&d, 1) != sizeof(double))
00444 return false;
00445 else
00446 {
00447 val.setReal(d);
00448 return true;
00449 }
00450 }
00451
00452 case VLB_ChunkString:
00453 if (!readString(str))
00454 return false;
00455 else
00456 {
00457 val.setString(str.c_str());
00458 return true;
00459 }
00460
00461 case VLB_ChunkIdentifier:
00462 if (!readString(str))
00463 return false;
00464 else
00465 {
00466 val.setIdentifier(str.c_str());
00467 return true;
00468 }
00469
00470 case VLB_ChunkID:
00471 if (!readString(str))
00472 return false;
00473 else
00474 {
00475 val.setID(str.c_str());
00476 return true;
00477 }
00478
00479 case VLB_ChunkBool:
00480 {
00481 unsigned char boolean = false;
00482 if ( inputFile()->readUInt8(&boolean, 1) != 1 )
00483 return false;
00484 else
00485 {
00486 val.setBool( boolean != 0 );
00487 return true;
00488 }
00489 }
00490
00491 default:
00492 return false;
00493
00494 }
00495 }
00496
00497 void setInputFile(VirtualFile* file) { mInputFile = file; }
00498
00499 VirtualFile* inputFile() { return mInputFile.get(); }
00500
00501 const VirtualFile* inputFile() const { return mInputFile.get(); }
00502
00503 private:
00504 unsigned int mFlags;
00505 ref<VirtualFile> mInputFile;
00506 };
00507 }
00508
00509 #endif