Thea
BinaryOutputStream.hpp
1 //============================================================================
2 //
3 // This file is part of the Thea toolkit.
4 //
5 // This software is distributed under the BSD license, as detailed in the
6 // accompanying LICENSE.txt file. Portions are derived from other works:
7 // their respective licenses and copyright information are reproduced in
8 // LICENSE.txt and/or in the relevant source files.
9 //
10 // Author: Siddhartha Chaudhuri
11 // First version: 2013
12 //
13 //============================================================================
14 
15 /*
16  ORIGINAL HEADER
17 
18  @file BinaryOutputStream.h
19 
20  @maintainer Morgan McGuire, graphics3d.com
21 
22  @created 2001-08-09
23  @edited 2008-01-24
24 
25  Copyright 2000-2006, Morgan McGuire.
26  All rights reserved.
27 */
28 
29 #ifndef __Thea_BinaryOutputStream_hpp__
30 #define __Thea_BinaryOutputStream_hpp__
31 
32 #ifdef _MSC_VER
33 // Disable conditional expression is constant, which occurs incorrectly on inlined functions
34 # pragma warning(push)
35 # pragma warning( disable : 4127 )
36 #endif
37 
38 #include "Common.hpp"
39 #include "Array.hpp"
40 #include "Codec.hpp"
41 #include "Colors.hpp"
42 #include "CoordinateFrame3.hpp"
43 #include "MatVec.hpp"
44 #include "NamedObject.hpp"
45 #include "Noncopyable.hpp"
46 #include "Plane3.hpp"
47 #include <algorithm>
48 #include <cstdarg>
49 #include <cstring>
50 
51 namespace Thea {
52 
67 class THEA_API BinaryOutputStream : public NamedObject, private Noncopyable
68 {
69  private:
71  Endianness m_fileEndian;
72 
74  std::string m_path;
75 
77  int m_beginEndBits;
78 
83  uint8 m_bitString;
84 
86  int m_bitPos;
87 
89  bool m_swapBytes;
90 
92  uint8 * m_buffer;
93 
95  int64 m_bufferLen;
96 
98  int64 m_bufferCapacity;
99 
101  int64 m_pos;
102 
104  int64 m_alreadyWritten;
105 
107  bool m_ok;
108 
110  void reserveBytesWhenOutOfMemory(size_t bytes);
111 
113  void reallocBuffer(size_t bytes, size_t oldBufferLen);
114 
116  void reserveBytes(int64 num_bytes)
117  {
118  debugAssertM(num_bytes > 0, getNameStr() + ": Can't reserve less than one byte");
119  size_t oldBufferLen = (size_t)m_bufferLen;
120  m_bufferLen = std::max(m_bufferLen, (m_pos + num_bytes));
121 
122  if (m_bufferLen > m_bufferCapacity)
123  reallocBuffer((size_t)num_bytes, oldBufferLen);
124  }
125 
127  bool _commit(bool flush, bool force);
128 
129  // Not implemented on purpose, don't use.
130  bool operator==(BinaryOutputStream const &);
131 
132  public:
133  THEA_DECL_SMART_POINTERS(BinaryOutputStream)
134 
135 
140  {
141  public:
144  : stream(stream_), saved_endian(stream_.getEndianness())
145  {}
146 
149  : stream(stream_), saved_endian(stream_.getEndianness())
150  {
151  stream.setEndianness(new_endian);
152  }
153 
155  ~EndiannessScope() { stream.setEndianness(saved_endian); }
156 
157  private:
158  BinaryOutputStream & stream;
159  Endianness saved_endian;
160 
161  }; // class EndiannessScope
162 
164  explicit BinaryOutputStream(Endianness endian = Endianness::LITTLE);
165 
171  BinaryOutputStream(std::string const & path, Endianness file_endian);
172 
175 
177  bool ok() const;
178 
183  void setEndianness(Endianness endian);
184 
187  {
188  return m_fileEndian;
189  }
190 
192  std::string getPath() const
193  {
194  return m_path;
195  }
196 
208  bool commit(bool flush = true);
209 
216  void commit(uint8 * dst) const;
217 
222  void reset();
223 
225  int64 size() const
226  {
227  return m_bufferLen + m_alreadyWritten;
228  }
229 
239  void setSize(int64 n)
240  {
241  n = n - m_alreadyWritten;
242 
243  if (n < 0)
244  throw Error(getNameStr() + ": Cannot resize huge files to be shorter");
245  else if (n < m_bufferLen)
246  {
247  m_bufferLen = n;
248  m_pos = n;
249  }
250  else if (n > m_bufferLen)
251  reserveBytes(n - m_pos);
252  }
253 
255  int64 getPosition() const
256  {
257  return m_pos + m_alreadyWritten;
258  }
259 
268  void setPosition(int64 p)
269  {
270  int64 q = p - m_alreadyWritten;
271 
272  if (q < 0)
273  throw Error(getNameStr() + ": Cannot seek too far backwards in a huge file");
274 
275  if (q > m_bufferLen)
276  setSize(p);
277 
278  m_pos = p - m_alreadyWritten;
279  }
280 
285  void skip(int64 n)
286  {
287  setPosition(m_pos + n);
288  }
289 
291  void writeBytes(int64 n, void const * b)
292  {
293  reserveBytes(n);
294 
295  debugAssertM(m_pos >= 0, getNameStr() + ": Invalid write position");
296  debugAssertM(m_bufferLen >= n, getNameStr() + format(": Could not reserve space to write %ld bytes", (intx)n));
297 
298  std::memcpy(m_buffer + m_pos, b, n);
299  m_pos += n;
300  }
301 
303  void writeUInt8(uint8 i)
304  {
305  reserveBytes(1);
306  m_buffer[m_pos] = i;
307  m_pos++;
308  }
309 
311  void writeInt8(int8 i)
312  {
313  reserveBytes(1);
314  m_buffer[m_pos] = *(uint8 *)&i;
315  m_pos++;
316  }
317 
319  void writeBool8(bool b)
320  {
321  writeUInt8(b ? 1 : 0);
322  }
323 
325  void writeUInt16(uint16 u);
326 
328  void writeInt16(int16 i)
329  {
330  writeUInt16(*(uint16 *)&i);
331  }
332 
334  void writeUInt32(uint32 u);
335 
337  void writeInt32(int32 i)
338  {
339  writeUInt32(*(uint32 *)&i);
340  }
341 
343  void writeUInt64(uint64 u);
344 
346  void writeInt64(int64 i)
347  {
348  writeUInt64(*(uint64 *)&i);
349  }
350 
352  void writeFloat32(float32 f)
353  {
354  debugAssertM(m_beginEndBits == 0, getNameStr() + ": Byte-level writes not allowed in a beginBits/endBits block");
355 
356  union
357  {
358  float32 a;
359  uint32 b;
360  };
361  a = f;
362  writeUInt32(b);
363  }
364 
366  void writeFloat64(float64 f)
367  {
368  debugAssertM(m_beginEndBits == 0, getNameStr() + ": Byte-level writes not allowed in a beginBits/endBits block");
369  union
370  {
371  float64 a;
372  uint64 b;
373  };
374  a = f;
375  writeUInt64(b);
376  }
377 
389  void THEA_CDECL printf(char const * fmt, ...) THEA_CHECK_MEMBER_PRINTF_ARGS;
390 
402  void THEA_CDECL vprintf(char const * fmt, va_list arg_list) THEA_CHECK_MEMBER_VPRINTF_ARGS;
403 
414  void writeString(std::string const & s)
415  {
416  writeAlignedString(s, 1);
417  }
418 
427  void writeAlignedString(std::string const & s, int alignment = 4);
428 
433  void beginBits();
434 
442  void writeBits(int num_bits, uint32 bit_string);
443 
448  void endBits();
449 
451  void writeVector2(Vector2 const & v)
452  {
453  writeFloat32(v.x());
454  writeFloat32(v.y());
455  }
456 
458  void writeVector3(Vector3 const & v)
459  {
460  writeFloat32(v.x());
461  writeFloat32(v.y());
462  writeFloat32(v.z());
463  }
464 
466  void writeVector4(Vector4 const & v)
467  {
468  writeFloat32(v.x());
469  writeFloat32(v.y());
470  writeFloat32(v.z());
471  writeFloat32(v.w());
472  }
473 
475  void writeColorL8(ColorL8 const & c)
476  {
477  writeUInt8(c.value());
478  }
479 
481  void writeColorL(ColorL const & c)
482  {
483  writeFloat32(c.value());
484  }
485 
487  void writeColorRgb8(ColorRgb8 const & c)
488  {
489  writeUInt8(c.r());
490  writeUInt8(c.g());
491  writeUInt8(c.b());
492  }
493 
495  void writeColorRgb(ColorRgb const & c)
496  {
497  writeFloat32(c.r());
498  writeFloat32(c.g());
499  writeFloat32(c.b());
500  }
501 
503  void writeColorRgba8(ColorRgba8 const & c)
504  {
505  writeUInt8(c.r());
506  writeUInt8(c.g());
507  writeUInt8(c.b());
508  writeUInt8(c.a());
509  }
510 
512  void writeColorRgba(ColorRgba const & c)
513  {
514  writeFloat32(c.r());
515  writeFloat32(c.g());
516  writeFloat32(c.b());
517  writeFloat32(c.a());
518  }
519 
521  void writeMatrix2(Matrix2 const & m)
522  {
523  writeFloat32(m(0, 0));
524  writeFloat32(m(0, 1));
525  writeFloat32(m(1, 0));
526  writeFloat32(m(1, 1));
527  }
528 
530  void writeMatrix3(Matrix3 const & m)
531  {
532  for (int r = 0; r < 3; ++r)
533  for (int c = 0; c < 3; ++c)
534  writeFloat32(m(r, c));
535  }
536 
538  void writeMatrix4(Matrix4 const & m)
539  {
540  for (int r = 0; r < 4; ++r)
541  for (int c = 0; c < 4; ++c)
542  writeFloat32(m(r, c));
543  }
544 
547  {
548  writeMatrix3(c.getRotation());
549  writeVector3(c.getTranslation());
550  }
551 
553  void writePlane3(Plane3 const & plane)
554  {
555  Real a, b, c, d;
556  plane.getEquation(a, b, c, d);
557  writeFloat32(a);
558  writeFloat32(b);
559  writeFloat32(c);
560  writeFloat32(d);
561  }
562 
571  template <typename MatrixT>
572  void writeMatrix(MatrixT const & m, Codec const & codec, bool write_block_header = false);
573 
574 #define THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(fname, tname)\
575  void write##fname(int64 n, tname const * out); \
576  void write##fname(int64 n, Array<tname> const & out);
577 
578  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Bool8, bool)
579  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(UInt8, uint8)
580  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Int8, int8)
581  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(UInt16, uint16)
582  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Int16, int16)
583  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(UInt32, uint32)
584  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Int32, int32)
585  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(UInt64, uint64)
586  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Int64, int64)
587  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Float32, float32)
588  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Float64, float64)
589  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Vector2, Vector2)
590  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Vector3, Vector3)
591  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Vector4, Vector4)
592  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorL8, ColorL8)
593  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorL, ColorL)
594  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorRgb8, ColorRgb8)
595  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorRgb, ColorRgb)
596  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorRgba8, ColorRgba8)
597  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(ColorRgba, ColorRgba)
598  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Matrix2, Matrix2)
599  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Matrix3, Matrix3)
600  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Matrix4, Matrix4)
601  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(CoordinateFrame3, CoordinateFrame3)
602  THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER(Plane3, Plane3)
603 #undef THEA_BINARY_OUTPUT_STREAM_DECLARE_WRITER
604 
605 }; // class BinaryOutputStream
606 
607 } // namespace Thea
608 
609 #ifdef _MSC_VER
610 # pragma warning (pop)
611 #endif
612 
613 THEA_DECL_EXTERN_SMART_POINTERS(Thea::BinaryOutputStream)
614 
615 #include "MatrixIO.hpp"
616 
617 #endif
void writeCoordinateFrame3(CoordinateFrame3 const &c)
Write a coordinate frame.
A base class for objects that should never be copied.
Definition: Noncopyable.hpp:28
Endianness values (little-endian and big-endian) (enum class).
void writeFloat32(float32 f)
Write a 32-bit floating point number.
void writeUInt8(uint8 i)
Write an unsigned 8-bit integer.
A color with three floating-point channels: red, green and blue, each in [0, 1].
Definition: ColorRgb.hpp:51
uint8 r() const
The value of the red channel.
Definition: ColorRgba8.hpp:74
Real g() const
The value of the green channel.
Definition: ColorRgb.hpp:111
Real b() const
The value of the blue channel.
Definition: ColorRgba.hpp:97
void setSize(int64 n)
Sets the length of the stream to n.
std::ptrdiff_t intx
A signed integer suitable for indexing a structure held in memory.
Definition: Platform.hpp:161
EndiannessScope(BinaryOutputStream &stream_, Endianness new_endian)
Constructor, saves the endianness state of a stream and sets a new endianness.
uint8 g() const
The value of the green channel.
Definition: ColorRgb8.hpp:83
void writeColorL(ColorL const &c)
Write a color with 1 floating-point channel.
void writeBytes(int64 n, void const *b)
Write a sequence of bytes.
Root namespace for the Thea library.
void writeInt8(int8 i)
Write a signed 8-bit integer.
void writePlane3(Plane3 const &plane)
Write a 3D plane.
void skip(int64 n)
Skips ahead n bytes (can skip past end-of-file, in which case the newly added bytes have undefined va...
void writeVector2(Vector2 const &v)
Write a 2-vector.
Real g() const
The value of the green channel.
Definition: ColorRgba.hpp:91
void writeColorRgba8(ColorRgba8 const &c)
Write a color with 4 8-bit channels.
EndiannessScope(BinaryOutputStream &stream_)
Constructor, saves the endianness state of a stream.
Monochrome luminance value represented as a single byte value in [0, 255], with automatic scaling by ...
Definition: ColorL8.hpp:46
VectorT const & getTranslation() const
Get translation component.
An object wrapping a name string.
Definition: NamedObject.hpp:58
A color with three byte-sized channels: red, green and blue, each in [0, 255].
Definition: ColorRgb8.hpp:47
A color with four byte-sized channels: red, green, blue and alpha, each in [0, 255].
Definition: ColorRgba8.hpp:47
void writeInt64(int64 i)
Write a signed 64-bit integer.
int64 getPosition() const
Returns the current byte position in the file, where 0 is the beginning and size() - 1 is the end...
uint8 b() const
The value of the blue channel.
Definition: ColorRgb8.hpp:89
Vector< N+1, T > getEquation() const
Get the coefficients {a_i} of the hyperplane equation a_0 * x_0 + a_1 * x_1 + ... ...
Real b() const
The value of the blue channel.
Definition: ColorRgb.hpp:117
std::string getPath() const
Get the path to the current file being written ("<memory>" for memory streams).
uint8 b() const
The value of the blue channel.
Definition: ColorRgba8.hpp:86
std::string format(char const *fmt,...)
Produces a string from arguments in the style of printf.
Definition: StringAlg.cpp:305
Real a() const
The value of the alpha channel.
Definition: ColorRgba.hpp:103
uint8 r() const
The value of the red channel.
Definition: ColorRgb8.hpp:77
MatrixT const & getRotation() const
Get rotation component.
void writeColorRgb8(ColorRgb8 const &c)
Write a color with 3 8-bit channels.
Monochrome luminance value in [0, 1], with automatic scaling by 255 when switching between integer (C...
Definition: ColorL.hpp:46
void writeBool8(bool b)
Write an 8-bit boolean value (0 for false, non-zero for true).
A serialization codec.
Definition: Codec.hpp:33
Endianness getEndianness() const
Get the endianness of current multi-byte write operations.
~EndiannessScope()
Destructor, restores the saved endianness of the stream.
void writeColorL8(ColorL8 const &c)
Write a color with 1 8-bit channel.
Real r() const
The value of the red channel.
Definition: ColorRgba.hpp:85
void writeColorRgb(ColorRgb const &c)
Write a color with 3 floating-point channels.
void writeInt32(int32 i)
Write a signed 32-bit integer.
void writeInt16(int16 i)
Write a signed 16-bit integer.
void writeFloat64(float64 f)
Write a 64-bit floating point number.
Real value() const
The value of the color.
Definition: ColorL.hpp:67
void writeMatrix3(Matrix3 const &m)
Write a 3x3 matrix.
uint8 g() const
The value of the green channel.
Definition: ColorRgba8.hpp:80
void writeVector3(Vector3 const &v)
Write a 3-vector.
void writeMatrix4(Matrix4 const &m)
Write a 4x4 matrix.
void writeString(std::string const &s)
Write a string.
A color with four floating-point channels: red, green and blue, each in [0, 1].
Definition: ColorRgba.hpp:52
std::runtime_error Error
An error class.
Definition: Error.hpp:27
void setPosition(int64 p)
Sets the position.
Sequential or random access output to binary files/memory.
An object that saves the current endianness state of a stream upon construction, and restores the pre...
void writeVector4(Vector4 const &v)
Write a 4-vector.
void writeMatrix2(Matrix2 const &m)
Write a 2x2 matrix.
uint8 a() const
The value of the alpha channel.
Definition: ColorRgba8.hpp:92
uint8 value() const
The value of the color.
Definition: ColorL8.hpp:67
Real r() const
The value of the red channel.
Definition: ColorRgb.hpp:105
void writeColorRgba(ColorRgba const &c)
Write a color with 3 floating-point channels.
int64 size() const
Get the total number of bytes written.
void debugAssertM(CondT const &test, MessageT const &msg)
Check if a test condition is true, and immediately abort the program with an error code if not...
Definition: Common.hpp:52