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
40namespace Alembic {
41namespace Ogawa {
42namespace ALEMBIC_VERSION_NS {
43
44class OStream::PrivateData
45{
46public:
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
100OStream::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
107OStream::OStream(std::ostream * iStream) : mData(new PrivateData(iStream))
108{
109 init();
110}
111
112OStream::~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
122bool OStream::isValid()
123{
124 return mData->stream != NULL;
125}
126
127void 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
154Alembic::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
173void 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
182void 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
#define FIELD3D_MTX_T
Definition StdMathLib.h:99