Field3D
OStream.cpp
Go to the documentation of this file.
1 //-*****************************************************************************
2 //
3 // Copyright (c) 2013,
4 // Sony Pictures Imageworks Inc. and
5 // Industrial Light & Magic, a division of Lucasfilm Entertainment Company Ltd.
6 //
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are
11 // met:
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above
15 // copyright notice, this list of conditions and the following disclaimer
16 // in the documentation and/or other materials provided with the
17 // distribution.
18 // * Neither the name of Industrial Light & Magic nor the names of
19 // its contributors may be used to endorse or promote products derived
20 // from this software without specific prior written permission.
21 //
22 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 //
34 //-*****************************************************************************
35 
36 #include "OStream.h"
37 #include <fstream>
38 #include <stdexcept>
39 
40 namespace Alembic {
41 namespace Ogawa {
42 namespace ALEMBIC_VERSION_NS {
43 
44 class OStream::PrivateData
45 {
46 public:
47  PrivateData(const std::string & iFileName) :
48  stream(NULL), fileName(iFileName), startPos(0)
49  {
50  std::ofstream * filestream = new std::ofstream(fileName.c_str(),
51  std::ios_base::trunc | std::ios_base::binary);
52  if (filestream->is_open())
53  {
54  stream = filestream;
55  stream->exceptions ( std::ofstream::failbit |
56  std::ofstream::badbit );
57  }
58  else
59  {
60  filestream->close();
61  delete filestream;
62  }
63  }
64 
65  PrivateData(std::ostream * iStream) : stream(iStream), startPos(0)
66  {
67  if (stream)
68  {
69  stream->exceptions ( std::ostream::failbit |
70  std::ostream::badbit );
71 
72  startPos = stream->tellp();
73  if (startPos == INVALID_DATA)
74  {
75  throw std::runtime_error("Illegal start of Ogawa stream");
76  }
77  }
78  }
79 
80  ~PrivateData()
81  {
82  // if this was done via file, try to clean it up
83  if (!fileName.empty() && stream)
84  {
85  std::ofstream * filestream = dynamic_cast<std::ofstream *>(stream);
86  if (filestream)
87  {
88  filestream->close();
89  delete filestream;
90  }
91  }
92  }
93 
94  std::ostream * stream;
95  std::string fileName;
96  Alembic::Util::uint64_t startPos;
97  Alembic::Util::mutex lock;
98 };
99 
100 OStream::OStream(const std::string & iFileName) :
101  mData(new PrivateData(iFileName))
102 {
103  init();
104 }
105 
106 // we'll be writing from this already open stream which we don't own
107 OStream::OStream(std::ostream * iStream) : mData(new PrivateData(iStream))
108 {
109  init();
110 }
111 
112 OStream::~OStream()
113 {
114  // write our "frozen" byte (totally done writing)
115  if (isValid())
116  {
117  char frozen = 0xff;
118  mData->stream->seekp(mData->startPos + 5).write(&frozen, 1).flush();
119  }
120 }
121 
122 bool OStream::isValid()
123 {
124  return mData->stream != NULL;
125 }
126 
127 void OStream::init()
128 {
129  // simple temporary endian check
130  union {
131  Util::uint32_t l;
132  char c[4];
133  } u;
134 
135  u.l = 0x01234567;
136 
137  if (u.c[0] != 0x67)
138  {
139  throw std::runtime_error(
140  "Ogawa currently only supports little-endian writing.");
141  }
142 
143  if (isValid())
144  {
145  const char header[] = {
146  'O', 'g', 'a', 'w', 'a', // special magic number
147  0, // this will be 0xff when the entire archive is done
148  0, 1, // 16 bit format version number
149  0, 0, 0, 0, 0, 0, 0, 0}; // position of the first group
150  mData->stream->write(header, sizeof(header)).flush();
151  }
152 }
153 
154 Alembic::Util::uint64_t OStream::getAndSeekEndPos()
155 {
156  if (isValid())
157  {
158  Alembic::Util::scoped_lock l(mData->lock);
159  Alembic::Util::uint64_t lastp =
160  mData->stream->seekp(0, std::ios_base::end).tellp();
161  if (lastp == INVALID_DATA || lastp < mData->startPos)
162  {
163  throw std::runtime_error(
164  "Illegal position returned Ogawa::OStream::getAndSeekEndPos");
165 
166  return 0;
167  }
168  return lastp - mData->startPos;
169  }
170  return 0;
171 }
172 
173 void OStream::seek(Alembic::Util::uint64_t iPos)
174 {
175  if (isValid())
176  {
177  Alembic::Util::scoped_lock l(mData->lock);
178  mData->stream->seekp(iPos + mData->startPos);
179  }
180 }
181 
182 void OStream::write(const void * iBuf, Alembic::Util::uint64_t iSize)
183 {
184  if (isValid())
185  {
186  Alembic::Util::scoped_lock l(mData->lock);
187  mData->stream->write((const char *)iBuf, iSize).flush();
188  }
189 }
190 
191 } // End namespace ALEMBIC_VERSION_NS
192 } // End namespace Ogawa
193 } // End namespace Alembic
Alembic
Definition: OgawaFwd.h:77