/**
  * Read the file designated by @a filename and fill @a output.
  */
 void GRxFileIO::Read(const std::string& filename, Acquisition::Pointer output)
 {
   output->Reset();
   IEEELittleEndianBinaryFileStream bifs;
   bifs.SetExceptions(BinaryFileStream::EndFileBit | BinaryFileStream::FailBit | BinaryFileStream::BadBit);
   try
   {
     bifs.Open(filename, BinaryFileStream::In);
     uint16_t numFra = bifs.ReadU16();
     double freq = static_cast<double>(bifs.ReadU16());
     // Some values between the bytes 0x05 and 0x49...
     // Bytes 50-51: Number of frames in the main acquisition + 1 and multiplied by 10...
     // Bytes 52-53: 0x00
     bifs.SeekRead(50, BinaryFileStream::Current);
     // Bytes 54-55: First frame 
     double ff = bifs.ReadU16();
     // Bytes 56-57: 0x00
     // Bytes 58-59: Last frame
     // Bytes 60-135 Other values ...
     bifs.SeekRead(80, BinaryFileStream::Current);
     // Bytes 136-139: Length
     double length = bifs.ReadFloat();
     // Bytes 140-143: Width
     double width = bifs.ReadFloat();
     // Bytes 144-147: Height
     double height = bifs.ReadFloat();
     // Corners 1,2,3,4: coordinates X,Y,Z
     std::vector<float> cornersData = bifs.ReadFloat(3*4);
     
     output->Init(0, numFra, 6, 1);
     output->SetFirstFrame(static_cast<int>(ceil(ff / 1000.0 * freq + 1.0)));
     output->SetPointFrequency(freq);
     // Metadata FORCE_PLATFORM
     MetaData::Pointer fp = MetaDataCreateChild(output->GetMetaData(), "FORCE_PLATFORM");
     // Metadata FORCE_PLATFORM:USED
     MetaDataCreateChild(fp, "USED", (int16_t)1);
     // Metadata FORCE_PLATFORM:ZERO
     std::vector<int16_t> zeros = std::vector<int16_t>(2,0);
     MetaDataCreateChild(fp, "ZERO", zeros);
     // Metadata FORCE_PLATFORM:TYPE
     MetaDataCreateChild(fp, "TYPE")->SetInfo(MetaDataInfo::New(std::vector<uint8_t>(1,1), std::vector<int16_t>(1,1)));
     // Metadata FORCE_PLATFORM:CORNERS
     std::vector<uint8_t> cornersDim = std::vector<uint8_t>(3, 1); cornersDim[0] = 3; cornersDim[1] = 4;
     MetaDataCreateChild(fp, "CORNERS")->SetInfo(MetaDataInfo::New(cornersDim, cornersData));
     // Metadata FORCE_PLATFORM:ORIGIN
     std::vector<uint8_t> originDim = std::vector<uint8_t>(2, 1); originDim[0] = 3;
     std::vector<float> originVal = std::vector<float>(3);
     originVal[0] = static_cast<float>(length / 2.0);
     originVal[1] = static_cast<float>(width / 2.0);
     originVal[2] = static_cast<float>(-1.0 * height / 2.0);
     MetaDataCreateChild(fp, "ORIGIN")->SetInfo(MetaDataInfo::New(originDim, originVal));
     // Metadata FORCE_PLATFORM:CHANNEL
     std::vector<uint8_t> channelDim = std::vector<uint8_t>(2, 1); channelDim[0] = 6;
     std::vector<int16_t> channelData = std::vector<int16_t>(6,0);
     channelData[0] = 1; channelData[1] = 2; channelData[2] = 3; channelData[3] = 4; channelData[4] = 5; channelData[5] = 6;
     MetaDataCreateChild(fp, "CHANNEL")->SetInfo(MetaDataInfo::New(channelDim, channelData));
     
     bifs.SeekRead(512, BinaryFileStream::Begin);
     btk::Wrench::Pointer fpw = btk::Wrench::New(numFra);
     for (int i = 0 ; i < output->GetPointFrameNumber() ; ++i)
     {
       output->GetAnalog(1)->GetValues().coeffRef(i) = bifs.ReadFloat();
       output->GetAnalog(0)->GetValues().coeffRef(i) = -1.0 * bifs.ReadFloat();
       output->GetAnalog(2)->GetValues().coeffRef(i) = -1.0 * bifs.ReadFloat();
       output->GetAnalog(4)->GetValues().coeffRef(i) = bifs.ReadFloat() - width / 2.0;
       output->GetAnalog(3)->GetValues().coeffRef(i) = -1.0 * bifs.ReadFloat() + length / 2.0;
       output->GetAnalog(5)->GetValues().coeffRef(i) = bifs.ReadFloat();
     }
     
     // Label channels
     std::string str = std::string(1, 0x00); str[0] = *(filename.rbegin());
     output->GetAnalog(0)->SetLabel("Fx" + str);
     output->GetAnalog(1)->SetLabel("Fy" + str);
     output->GetAnalog(2)->SetLabel("Fz" + str);
     output->GetAnalog(3)->SetLabel("Px" + str);
     output->GetAnalog(4)->SetLabel("Py" + str);
     output->GetAnalog(5)->SetLabel("Mz" + str);
   }
   catch (BinaryFileStreamFailure& )
   {
     std::string excmsg; 
     if (bifs.EndFile())
       excmsg = "Unexpected end of file.";
     else if (!bifs.IsOpen())
       excmsg = "Invalid file path.";
     else if(bifs.Bad())
       excmsg = "Loss of integrity of the file stream.";
     else if(bifs.Fail())
       excmsg = "Internal logic operation error on the stream associated with the file.";
     else
       excmsg = "Unknown error associated with the file stream.";
     
     if (bifs.IsOpen()) bifs.Close();    
     throw(GRxFileIOException(excmsg));
   }
   catch (GRxFileIOException& )
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw;
   }
   catch (std::exception& e)
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw(GRxFileIOException("Unexpected exception occurred: " + std::string(e.what())));
   }
   catch(...)
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw(GRxFileIOException("Unknown exception"));
   }
 };
 /**
  * Read the file designated by @a filename and fill @a output.
  */
 void KistlerDATFileIO::Read(const std::string& filename, Acquisition::Pointer output)
 {
   output->Reset();
   IEEELittleEndianBinaryFileStream bifs;
   bifs.SetExceptions(BinaryFileStream::EndFileBit | BinaryFileStream::FailBit | BinaryFileStream::BadBit);
   try
   {
     bifs.Open(filename, BinaryFileStream::In);
     // WARNING: The header key is maybe not a key but the number of force platforms in the file!
     if (bifs.ReadI32() != 2)
       throw(KistlerDATFileIOException("Wrong header key. It is not a proper Kistler DAT file."));
     
     // NOTE: It seems there are several headers in the file. A general header at the beginning
     // which resume acquisition's information (number of channels, number of frames, sample 
     // rate, ...) and another one for each force plate. It is not yet clear
     
     // General header?
     // ---------------
     // FIXME: What is the meaning of the next 12 bytes?
     bifs.SeekRead(12, BinaryFileStream::Current);
     // FIXME: What are the next (numel+4)*4 bytes, seems to be a table.
     int32_t tableDims[2];
     bifs.ReadI32(2,tableDims);
     int32_t numel = tableDims[0] * tableDims[1] * 4;
     bifs.SeekRead(4, BinaryFileStream::Current); // Space?
     bifs.SeekRead(numel, BinaryFileStream::Current); // Table data?
     bifs.SeekRead(4, BinaryFileStream::Current); // Space again?
     // FIXME: What is the meaning of the next 22 bytes?
     bifs.SeekRead(22, BinaryFileStream::Current);
     // The next offsets given in the comments start at 16+(numel+4)*4+22.
     // 0x00: (int32) Number of channels
     int numberOfChannels = bifs.ReadI32();
     // 0x04: (int32) Number of frames
     int numberOfFrames = bifs.ReadI32();
     // 0x08: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x12: (int32) ADC resolution? Number of ADC channels on the board?
     int digitalResolution = bifs.ReadI32();
     // 0x16: (double) Sample frequency
     double sampleFrequency = bifs.ReadDouble();
     // 0x24: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x28: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x32: Normalized force (N) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x36: Normalized length (mm) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x40: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x44: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x48: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x52: ?? (Could be an index) 
     bifs.SeekRead(2, BinaryFileStream::Current);
     // 0x54: (int16_t) Number of characters (n) in the next string
     // 0x56: (string) What is this string? - SKIPPED
     bifs.SeekRead(bifs.ReadU16(), BinaryFileStream::Current);
     
     // Force plate header?
     // -------------------
     // For simplification the adress in the description is reset to 0, but this is right after
     // the general header, so add 94+(numel+4)*4+n to find the good position in a file.
     // 0x00: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x04: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x08: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x12: (int32) Number of channels
     if (bifs.ReadI32() != numberOfChannels)
       throw(KistlerDATFileIOException("Wrong number of channels declared."));
     // 0x16: (int32) Number of frames
     if (bifs.ReadI32() != numberOfFrames)
       throw(KistlerDATFileIOException("Wrong number of frames declared."));
     // 0x20: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x24: (int32) ADC resolution
     if (bifs.ReadI32() != digitalResolution)
       throw(KistlerDATFileIOException("Wrong ADC resolution declared."));
     // 0x28: (double) sample frequency
     if (bifs.ReadDouble() != sampleFrequency)
       throw(KistlerDATFileIOException("Wrong sample frequency declared."));
     // 0x36: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x40: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x44: (int32) Normalized force (N) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x48: (int32) Normalized length (mm) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x52: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x56: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x60: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x64: (uint8) Number of characters (i) for the manufacturer of the force plateform
     // 0x65: (string) Manufacter of the force plateform - SKIPPED
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current);
     // 0x65+i: (int16) Number of characters (j) for the reference of the force plateform
     // 0x66+i: (string) Reference of the force plateform - SKIPPED
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current);
     // 0x66+i+j: (uint8) Number of characters (k) for the ? (serial number?)
     // 0x67+i+j: (string) (Serial number?) of the force plateform - SKIPPED
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current);
     // 0x67+i+j+k: (int32) Contact period start (sample #) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x71+i+j+k: (int32) Contact period end (sample #) - SKIPPED
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x75+i+j+k: ?? - Seems to be a double
     bifs.SeekRead(8, BinaryFileStream::Current);
     // 0x83+i+j+k: ??
     bifs.SeekRead(4, BinaryFileStream::Current);
     // 0x87+i+j+k: (double) FP width (mm)
     double width = bifs.ReadDouble();
     // 0x95+i+j+k: (double) FP length (mm)
     double length = bifs.ReadDouble();
     // 0x103+i+j+k: (double) FP a (mm)
     double a = bifs.ReadDouble();
     // 0x111+i+j+k: (double) FP b (mm)
     double b = bifs.ReadDouble();
     // What are the next 24 bytes? They are set to 0.
     bifs.SeekRead(24, BinaryFileStream::Current);
     // Why the parameter az0 is repeated two times?
     double az0 = bifs.ReadDouble();
     bifs.SeekRead(8, BinaryFileStream::Current); // az0 is written a second time
     // The next values are 3 strings which contain the word "INTEGRATED"
     // Maybe this is related to know if the component of each sensor is linked to built-in charge amplifier
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current); // Integrated
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current); // Integrated
     bifs.SeekRead(bifs.ReadU8(), BinaryFileStream::Current); // Integrated
     // Next double value could be the output voltage
     bifs.SeekRead(8, BinaryFileStream::Current);
     // Next 8 double values could be a scale factor for the amplifier (pC->V)
     // Blank of 64 bytes (could be for 8 other channels?)
     bifs.SeekRead(128, BinaryFileStream::Current);
     // Next 8 double values could be the calibrated partial range
     // Blank of 64 bytes (could be for 8 other channels?)
     bifs.SeekRead(128, BinaryFileStream::Current);
     // There is then 104 blank bytes
     bifs.SeekRead(104, BinaryFileStream::Current);
     
     // Initialize the output
     output->Init(0,numberOfFrames,numberOfChannels);
     output->SetPointFrequency(sampleFrequency);
     
     // Then the real (float) measured values (Fx12, Fx34, Fy14, Fy23, Fz1, Fz2, Fz4) directly in newtons
     // WARNING: These values are stored by channels and not by samples
     int inc = 0;
     const char* labels[8] = {"Fx12", "Fx34", "Fy14", "Fy23", "Fz1", "Fz2", "Fz3", "Fz4"};
     for (Acquisition::AnalogIterator it = output->BeginAnalog() ; it != output->EndAnalog() ; ++it)
     {
       (*it)->SetLabel(labels[inc++]);
       (*it)->SetUnit("N");
       for (int i = 0 ; i < numberOfFrames ; ++i)
         (*it)->GetValues().coeffRef(i) = -1.0 * bifs.ReadFloat(); // -1.0: BTK stores the reaction.
     }
     
     // Compute the origin and the coordinates of the corners
     std::vector<float> corners(12);
     std::vector<float> origin(3);
     // TODO: The next lines could be factorized with the code of the method AMTIForcePlatformFileIO::computeGeometryFromDimensions
     float cx = static_cast<float>(width) / 2.0f;
     float cy = static_cast<float>(length) / 2.0f;
     // Corners expressed in the global frame.
     // The global frame is set here as: axis X going forward, axis Y on the left and axis Z going upward.
     // The corners are set to have the corner #1 on the bottom left side, #2 on the top left side, #3 on the top right side and #4 on the bottom right side.
     corners[0] = cx;
     corners[1] = -cy;
     corners[2] = 0.0f;
     corners[3] = -cx;
     corners[4] = -cy;
     corners[5] = 0.0f;
     corners[6] = -cx;
     corners[7] = cy;
     corners[8] = 0.0f;
     corners[9] = cx;
     corners[10] = cy;
     corners[11] = 0.0f;
     // - Origin (expressed in the global frame) and centered above the origin of the global frame
     origin[0] = (float)a;
     origin[1] = (float)b;
     origin[2] = (float)az0;
     
     // Create the metadata FORCE_PLATFORM
     btk::MetaData::Pointer forcePlatform = btk::MetaData::New("FORCE_PLATFORM");
     output->GetMetaData()->AppendChild(forcePlatform);
     // - FORCE_PLATFORM:USED
     forcePlatform->AppendChild(btk::MetaData::New("USED", static_cast<int16_t>(1)));
     // - FORCE_PLATFORM:TYPE
     forcePlatform->AppendChild(btk::MetaData::New("TYPE", std::vector<int16_t>(1,3)));
     // - FORCE_PLATFORM:ZERO
     std::vector<int16_t> zero(2,0); zero[0] = 1;
     forcePlatform->AppendChild(btk::MetaData::New("ZERO", zero));
     // - FORCE_PLATFORM:CORNERS
     std::vector<uint8_t> dims(3); dims[0] = 3; dims[1] = 4; dims[2] = 1;
     forcePlatform->AppendChild(btk::MetaData::New("CORNERS", dims, corners));
     // - FORCE_PLATFORM:ORIGIN
     dims.resize(2); dims[0] = 3; dims[1] = 1;
     forcePlatform->AppendChild(btk::MetaData::New("ORIGIN", dims, origin));
     // - FORCE_PLATFORM:CHANNEL
     dims.resize(2); dims[0] = 8; dims[1] = 1;
     std::vector<int16_t> channel(8);
     for (int i = 0 ; i < 8 ; ++i)
       channel[i] = i+1;
     forcePlatform->AppendChild(btk::MetaData::New("CHANNEL", dims, channel));
     // Add a metadata to notify that the first frame was not set.
     MetaData::Pointer btkPointConfig = MetaDataCreateChild(output->GetMetaData(), "BTK_POINT_CONFIG");
     MetaDataCreateChild(btkPointConfig, "NO_FIRST_FRAME", static_cast<int8_t>(1));
   }
   catch (BinaryFileStreamFailure& )
   {
     std::string excmsg; 
     if (bifs.EndFile())
       excmsg = "Unexpected end of file.";
     else if (!bifs.IsOpen())
       excmsg = "Invalid file path.";
     else if(bifs.Bad())
       excmsg = "Loss of integrity of the file stream.";
     else if(bifs.Fail())
       excmsg = "Internal logic operation error on the stream associated with the file.";
     else
       excmsg = "Unknown error associated with the file stream.";
     
     if (bifs.IsOpen()) bifs.Close();    
       throw(KistlerDATFileIOException(excmsg));
   }
   catch (KistlerDATFileIOException& )
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw;
   }
   catch (std::exception& e)
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw(KistlerDATFileIOException("Unexpected exception occurred: " + std::string(e.what())));
   }
   catch(...)
   {
     if (bifs.IsOpen()) bifs.Close(); 
     throw(KistlerDATFileIOException("Unknown exception"));
   }
 };