IODA Bundle
Header.cc
Go to the documentation of this file.
1 /*
2  * (C) Copyright 1996-2012 ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  * In applying this licence, ECMWF does not waive the privileges and immunities
7  * granted to it by virtue of its status as an intergovernmental organisation nor
8  * does it submit to any jurisdiction.
9  */
10 
11 #include "odc/core/Header.h"
12 
13 #include "eckit/io/DataHandle.h"
14 #include "eckit/io/Buffer.h"
15 #include "eckit/types/FixedString.h"
16 #include "eckit/utils/MD5.h"
17 
18 #include "odc/core/DataStream.h"
19 #include "odc/core/Exceptions.h"
20 #include "odc/core/MetaData.h"
21 #include "odc/ODBAPISettings.h"
22 
23 using namespace eckit;
24 
25 namespace odc {
26 namespace core {
27 
28 //----------------------------------------------------------------------------------------------------------------------
29 
30 Header::Header(MetaData& md, Properties& props) :
31  md_(md),
32  props_(props),
33  dataSize_(0),
34  rowsNumber_(0),
35  byteOrder_(BYTE_ORDER_INDICATOR) {}
36 
38 
39 bool Header::readMagic(DataHandle& dh) {
40 
41  eckit::FixedString<5> magic;
42 
43  long bytesRead = dh.read(&magic, sizeof(magic));
44  if (bytesRead == 0) return false;
45  if (bytesRead != sizeof(magic)) throw ODBIncomplete(dh.title(), Here());
46  if (magic != "\xff\xffODA") throw ODBInvalid(dh.title(), "Incorrect MAGIC", Here());
47  return true;
48 }
49 
50 template <typename ByteOrder>
51 void Header::load(DataHandle& dh) {
52 
53  // There must be at least 56 bytes available to read the basic header.
54 
55  constexpr size_t basic_header_size = 12 + 32 + 4;
56  char basicBuffer[basic_header_size];
57 
58  if (dh.read(basicBuffer, sizeof(basicBuffer)) != sizeof(basicBuffer)) throw ODBIncomplete(dh.title(), Here());
59 
60  DataStream<ByteOrder> ds1(basicBuffer, sizeof(basicBuffer));
61 
62  int32_t formatVersionMajor;
63  ds1.read(formatVersionMajor);
64  ASSERT("File format version not supported" && formatVersionMajor <= FORMAT_VERSION_NUMBER_MAJOR);
65 
66  int32_t formatVersionMinor;
67  ds1.read(formatVersionMinor);
68  ASSERT("File format version not supported" && formatVersionMinor <= FORMAT_VERSION_NUMBER_MINOR && formatVersionMinor > 3);
69 
70  std::string headerDigest;
71  ds1.read(headerDigest);
72 
73  int32_t headerSize;
74  ds1.read(headerSize);
75 
76  // Read the remaining header data
77 
78  eckit::Buffer buffer(headerSize);
79  if (dh.read(buffer, headerSize) != headerSize) throw ODBIncomplete(dh.title(), Here());
80 
81  // Calculate the MD5
82 
83  MD5 md5;
84  md5.add(buffer.data(), buffer.size());
85  std::string actualHeaderDigest = md5.digest();
86  if (headerDigest != actualHeaderDigest) throw ODBInvalid(dh.title(), "Header digest incorrect", Here());
87 
88  DataStream<ByteOrder> ds2(buffer, buffer.size());
89 
90  // 0 means we don't know offset of next header.
91  int64_t nextFrameOffset;
92  ds2.read(nextFrameOffset);
93  dataSize_ = nextFrameOffset;
95 
96  // Reserved, not used yet.
97  int64_t prevFrameOffset;
98  ds2.read(prevFrameOffset);
99  ASSERT(prevFrameOffset == 0);
100 
101  // TODO: increase file format version
102 
103  int64_t numberOfRows;
104  ds2.read(numberOfRows);
105  rowsNumber_ = numberOfRows;
107 
108  eckit::Log::debug() << "Header::load: numberOfRows = " << numberOfRows << std::endl;
109 
110  // Flags -> ODAFlags
111  Flags flags;
112  ds2.read(flags);
113 
114  ds2.read(props_);
115 
116  md_.load(ds2);
117 }
118 
119 void Header::loadAfterMagic(DataHandle& dh) {
120 
121  if (dh.read(&byteOrder_, sizeof(byteOrder_)) != sizeof(byteOrder_)) {
122  throw ODBIncomplete(dh.title(), Here());
123  }
124 
126  load<OtherByteOrder>(dh);
127  } else {
128  load<SameByteOrder>(dh);
129  }
130 }
131 
132 namespace {
133 
134 
135 template <typename ByteOrder>
136 std::pair<eckit::Buffer, size_t> serializeHeaderInternal(size_t dataSize, size_t rowsNumber, const Properties& properties, const MetaData& columns) {
137 
138  // Serialise the variable size part of the header first. Use the configured buffer size
139  // but allow expansion if needed.
140 
141  constexpr size_t initial_header_size = 9 + 8 + 4 + 32 + 4;
142 
143  eckit::Buffer buffer(ODBAPISettings::instance().headerBufferSize());
144  bool serialised = false;
145  char* variableHeaderStart = 0;
146  int32_t variableHeaderSize;
147 
148  while (!serialised) {
149  try {
150  variableHeaderStart = buffer + initial_header_size;
151  DataStream<ByteOrder> ds(variableHeaderStart, buffer.size() - initial_header_size);
152 
153  ds.write(static_cast<int64_t>(dataSize)); // Reserved: nextFrameOffset
154  ds.write(static_cast<int64_t>(0)); // Reserved: prevFrameOffset
155  ds.write(static_cast<int64_t>(rowsNumber)); // num. rows
156 
157  Flags flags(0); // n.b. flags unused
158  ds.write(flags);
159 
160  ds.write(properties);
161 
162  columns.save(ds);
163 
164  serialised = true;
165  variableHeaderSize = ds.position();
166 
167  } catch (ODBEndOfDataStream& e) {
168  buffer = eckit::Buffer(buffer.size() * 2);
169  }
170  }
171 
172  // Calculate MD5 of the variable portion of header data
173 
174  MD5 md5;
175  md5.add(variableHeaderStart, variableHeaderSize);
176  std::string headerDigest = md5.digest();
177 
178  // Now Serialise everything into the final buffer
179 
180  DataStream<ByteOrder> ds(buffer.data(), initial_header_size);
181 
182  // Header.
183  ds.write(static_cast<uint16_t>(ODA_MAGIC_NUMBER)); // MAGIC
184 
185  ds.write('O'); // MAGIC
186  ds.write('D'); // MAGIC
187  ds.write('A'); // MAGIC
188 
189  ds.write(static_cast<int32_t>(BYTE_ORDER_INDICATOR));
190  ds.write(static_cast<int32_t>(FORMAT_VERSION_NUMBER_MAJOR));
191  ds.write(static_cast<int32_t>(FORMAT_VERSION_NUMBER_MINOR));
192 
193  ds.write(headerDigest); // MD5
194 
195  ds.write(static_cast<int32_t>(variableHeaderSize)); // How much header data follows
196 
197  ASSERT(ds.position() == eckit::Offset(initial_header_size));
198 
199  return std::make_pair(std::move(buffer), variableHeaderSize + ds.position());
200 }
201 
202 }
203 
204 std::pair<Buffer, size_t> Header::serializeHeader(size_t dataSize, size_t rowsNumber, const Properties& properties, const MetaData& columns) {
205  return serializeHeaderInternal<SameByteOrder>(dataSize, rowsNumber, properties, columns);
206 }
207 
208 std::pair<Buffer, size_t> Header::serializeHeaderOtherByteOrder(size_t dataSize, size_t rowsNumber, const Properties& properties, const MetaData& columns) {
209  return serializeHeaderInternal<OtherByteOrder>(dataSize, rowsNumber, properties, columns);
210 }
211 
212 
213 //----------------------------------------------------------------------------------------------------------------------
214 
215 } // namespace core
216 } // namespace odc
217 
static ODBAPISettings & instance()
void read(T &elem)
Definition: DataStream.h:205
eckit::Offset position() const
Definition: DataStream.h:198
void write(const T &elem)
Definition: DataStream.h:276
void load(eckit::DataHandle &dh)
Definition: Header.cc:51
static bool readMagic(eckit::DataHandle &dh)
Definition: Header.cc:39
Properties & props_
Definition: Header.h:78
size_t dataSize_
Definition: Header.h:79
size_t rowsNumber() const
Definition: Header.h:57
size_t rowsNumber_
Definition: Header.h:80
MetaData & md_
Definition: Header.h:77
static std::pair< eckit::Buffer, size_t > serializeHeader(size_t dataSize, size_t rowsNumber, const Properties &properties, const MetaData &columns)
Definition: Header.cc:204
void loadAfterMagic(eckit::DataHandle &dh)
Definition: Header.cc:119
int32_t byteOrder_
Definition: Header.h:82
size_t dataSize() const
Definition: Header.h:55
static std::pair< eckit::Buffer, size_t > serializeHeaderOtherByteOrder(size_t dataSize, size_t rowsNumber, const Properties &properties, const MetaData &columns)
Definition: Header.cc:208
unsigned long long dataSize() const
Definition: MetaData.h:42
void load(DataStream< ByteStream > &ds)
unsigned long long rowsNumber() const
Definition: MetaData.h:39
std::pair< eckit::Buffer, size_t > serializeHeaderInternal(size_t dataSize, size_t rowsNumber, const Properties &properties, const MetaData &columns)
Definition: Header.cc:136
std::map< std::string, std::string > Properties
Definition: Header.h:35
const int32_t FORMAT_VERSION_NUMBER_MAJOR
Definition: Header.h:43
const uint16_t ODA_MAGIC_NUMBER
Definition: Header.h:41
const int32_t BYTE_ORDER_INDICATOR
Definition: Header.h:40
std::vector< double > Flags
Definition: Header.h:36
const int32_t FORMAT_VERSION_NUMBER_MINOR
Definition: Header.h:44
Definition: ColumnInfo.h:23