1
/******************************************************************************
4
* Project: libLAS - http://liblas.org - A BSD library for LAS format data.
5
* Purpose: LAS header writer implementation for C++ libLAS
6
* Author: Howard Butler, hobu.inc@gmail.com
8
******************************************************************************
9
* Copyright (c) 2010, Howard Butler
11
* All rights reserved.
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following
17
* * Redistributions of source code must retain the above copyright
18
* notice, this list of conditions and the following disclaimer.
19
* * Redistributions in binary form must reproduce the above copyright
20
* notice, this list of conditions and the following disclaimer in
21
* the documentation and/or other materials provided
22
* with the distribution.
23
* * Neither the name of the Martin Isenburg or Iowa Department
24
* of Natural Resources nor the names of its contributors may be
25
* used to endorse or promote products derived from this software
26
* without specific prior written permission.
28
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
35
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
36
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
37
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
38
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
40
****************************************************************************/
42
#include <liblas/header.hpp>
43
#include <liblas/point.hpp>
44
#include <liblas/spatialreference.hpp>
45
#include <liblas/detail/writer/header.hpp>
46
#include <liblas/detail/private_utility.hpp>
47
#include <liblas/detail/zippoint.hpp>
49
#include <boost/cstdint.hpp>
52
#include <cstdlib> // std::size_t
62
using namespace boost;
65
namespace liblas { namespace detail { namespace writer {
67
Header::Header(std::ostream& ofs, boost::uint32_t& count, liblas::Header const& header)
81
// Figure out how many points we already have.
82
// Figure out if we're in append mode. If we are, we can't rewrite
83
// any of the VLRs including the Schema and SpatialReference ones.
84
bool bAppendMode = false;
86
// This test should only be true if we were opened in both
87
// std::ios::in *and* std::ios::out
89
// Seek to the beginning
90
m_ofs.seekp(0, ios::beg);
91
ios::pos_type begin = m_ofs.tellp();
94
m_ofs.seekp(0, ios::end);
95
ios::pos_type end = m_ofs.tellp();
96
if ((begin != end) && (end != static_cast<ios::pos_type>(0))) {
100
// If we are in append mode, we are not touching *any* VLRs.
103
// We're opened in append mode
105
if (!m_header.Compressed())
107
ios::off_type points = end - static_cast<ios::off_type>(m_header.GetDataOffset());
108
ios::off_type count = points / static_cast<ios::off_type>(m_header.GetDataRecordLength());
111
std::ostringstream oss;
112
oss << "The header's data offset, " << m_header.GetDataOffset()
113
<<", is much larger than the size of the file, " << end
114
<<", and something is amiss. Did you use the right header"
116
throw std::runtime_error(oss.str());
119
m_pointCount = static_cast<uint32_t>(count);
122
m_pointCount = m_header.GetPointRecordsCount();
125
// Position to the beginning of the file to start writing the header
126
m_ofs.seekp(0, ios::beg);
132
// Rewrite the georeference VLR entries if they exist
133
m_header.DeleteVLRs("liblas", 2112);
134
m_header.SetGeoreference();
136
// If we have a custom schema, add the VLR and write it into the
138
if (m_header.GetSchema().IsCustom()) {
140
// Wipe any schema-related VLRs we might have, as this is now out of date.
141
m_header.DeleteVLRs("liblas", 7);
143
VariableRecord v = m_header.GetSchema().GetVLR();
144
std::cout << m_header.GetSchema()<< std::endl;
148
// add the laszip VLR, if needed
149
if (m_header.Compressed())
152
m_header.DeleteVLRs("laszip encoded", 22204);
153
ZipPoint zpd(m_header.GetDataFormatId(), m_header.GetVLRs());
158
throw configuration_error("LASzip compression support not enabled in this libLAS configuration.");
163
m_header.DeleteVLRs("laszip encoded", 22204);
166
int32_t existing_padding = m_header.GetDataOffset() -
167
(m_header.GetVLRBlockSize() +
168
m_header.GetHeaderSize());
170
if (existing_padding < 0)
172
int32_t d = abs(existing_padding);
174
// If our required VLR space is larger than we have
175
// room for, we have no padding. AddVLRs will take care
176
// of incrementing up the space it needs.
177
if (static_cast<boost::int32_t>(m_header.GetVLRBlockSize()) > d)
179
m_header.SetHeaderPadding(0);
181
m_header.SetHeaderPadding(d - m_header.GetVLRBlockSize());
184
// cast is safe, we've already checked for < 0
185
if (static_cast<uint32_t>(existing_padding) >= m_header.GetHeaderPadding())
187
m_header.SetHeaderPadding(existing_padding);
190
m_header.SetHeaderPadding(m_header.GetHeaderPadding() + existing_padding);
195
m_header.SetDataOffset( m_header.GetHeaderSize() +
196
m_header.GetVLRBlockSize() +
197
m_header.GetHeaderPadding());
202
std::string const filesig(m_header.GetFileSignature());
203
assert(filesig.size() == 4);
204
detail::write_n(m_ofs, filesig, 4);
207
// 2. File SourceId / Reserved
208
if (m_header.GetVersionMinor() == 0) {
209
n4 = m_header.GetReserved();
210
detail::write_n(m_ofs, n4, sizeof(n4));
211
} else if (m_header.GetVersionMinor() > 0) {
212
n2 = m_header.GetFileSourceId();
213
detail::write_n(m_ofs, n2, sizeof(n2));
214
n2 = m_header.GetReserved();
215
detail::write_n(m_ofs, n2, sizeof(n2));
222
uint8_t d4[8] = { 0 };
223
liblas::guid g = m_header.GetProjectId();
224
g.output_data(d1, d2, d3, d4);
225
detail::write_n(m_ofs, d1, sizeof(d1));
226
detail::write_n(m_ofs, d2, sizeof(d2));
227
detail::write_n(m_ofs, d3, sizeof(d3));
228
detail::write_n(m_ofs, d4, sizeof(d4));
231
n1 = m_header.GetVersionMajor();
233
detail::write_n(m_ofs, n1, sizeof(n1));
236
n1 = m_header.GetVersionMinor();
237
detail::write_n(m_ofs, n1, sizeof(n1));
240
std::string sysid(m_header.GetSystemId(true));
241
assert(sysid.size() == 32);
242
detail::write_n(m_ofs, sysid, 32);
244
// 10. Generating Software ID
245
std::string softid(m_header.GetSoftwareId(true));
246
assert(softid.size() == 32);
247
detail::write_n(m_ofs, softid, 32);
249
// 11. Flight Date Julian
250
n2 = m_header.GetCreationDOY();
251
detail::write_n(m_ofs, n2, sizeof(n2));
254
n2 = m_header.GetCreationYear();
255
detail::write_n(m_ofs, n2, sizeof(n2));
258
n2 = m_header.GetHeaderSize();
260
detail::write_n(m_ofs, n2, sizeof(n2));
262
// 14. Offset to data
263
n4 = m_header.GetDataOffset();
264
detail::write_n(m_ofs, n4, sizeof(n4));
266
// 15. Number of variable length records
267
n4 = m_header.GetRecordsCount();
268
detail::write_n(m_ofs, n4, sizeof(n4));
270
// 16. Point Data Format ID
271
n1 = static_cast<uint8_t>(m_header.GetDataFormatId());
273
if (m_header.Compressed()) // high bit set indicates laszip compression
275
detail::write_n(m_ofs, n1tmp, sizeof(n1tmp));
277
// 17. Point Data Record Length
278
n2 = m_header.GetDataRecordLength();
279
detail::write_n(m_ofs, n2, sizeof(n2));
281
// 18. Number of point records
282
// This value is updated if necessary, see UpdateHeader function.
283
n4 = m_header.GetPointRecordsCount();
284
detail::write_n(m_ofs, n4, sizeof(n4));
286
// 19. Number of points by return
287
std::vector<uint32_t>::size_type const srbyr = 5;
288
std::vector<uint32_t> const& vpbr = m_header.GetPointRecordsByReturnCount();
289
// TODO: fix this for 1.3, which has srbyr = 7; See detail/reader/header.cpp for more details
290
// assert(vpbr.size() <= srbyr);
291
uint32_t pbr[srbyr] = { 0 };
292
std::copy(vpbr.begin(), vpbr.begin() + srbyr, pbr); // FIXME: currently, copies only 5 records, to be improved
293
detail::write_n(m_ofs, pbr, sizeof(pbr));
295
// 20-22. Scale factors
296
detail::write_n(m_ofs, m_header.GetScaleX(), sizeof(double));
297
detail::write_n(m_ofs, m_header.GetScaleY(), sizeof(double));
298
detail::write_n(m_ofs, m_header.GetScaleZ(), sizeof(double));
301
detail::write_n(m_ofs, m_header.GetOffsetX(), sizeof(double));
302
detail::write_n(m_ofs, m_header.GetOffsetY(), sizeof(double));
303
detail::write_n(m_ofs, m_header.GetOffsetZ(), sizeof(double));
306
detail::write_n(m_ofs, m_header.GetMaxX(), sizeof(double));
307
detail::write_n(m_ofs, m_header.GetMinX(), sizeof(double));
310
detail::write_n(m_ofs, m_header.GetMaxY(), sizeof(double));
311
detail::write_n(m_ofs, m_header.GetMinY(), sizeof(double));
314
detail::write_n(m_ofs, m_header.GetMaxZ(), sizeof(double));
315
detail::write_n(m_ofs, m_header.GetMinZ(), sizeof(double));
321
// if we have padding, we should write it
322
if (m_header.GetHeaderPadding() > 0) {
323
m_ofs.seekp(m_header.GetHeaderSize() + m_header.GetVLRBlockSize(), std::ios::end);
324
detail::write_n(m_ofs, "\0", m_header.GetHeaderPadding());
327
// Write the 1.0 pad signature if we need to.
328
WriteLAS10PadSignature();
331
// If we already have points, we're going to put it at the end of the file.
332
// If we don't have any points, we're going to leave it where it is.
333
if (m_pointCount != 0)
335
m_ofs.seekp(0, std::ios::end);
339
m_ofs.seekp(m_header.GetDataOffset(), std::ios::beg);
344
void Header::WriteVLRs()
347
// Seek to the end of the public header block (beginning of the VLRs)
349
m_ofs.seekp(m_header.GetHeaderSize(), std::ios::beg);
351
int32_t diff = m_header.GetDataOffset() - GetRequiredHeaderSize();
355
m_header.SetDataOffset(GetRequiredHeaderSize());
356
// Seek to the location of the data offset in the header and write a new one.
357
m_ofs.seekp(96, std::ios::beg);
358
detail::write_n(m_ofs, m_header.GetDataOffset(), sizeof(m_header.GetDataOffset()));
359
m_ofs.seekp(m_header.GetHeaderSize(), std::ios::beg);
361
// std::ostringstream oss;
362
// oss << "Header is not large enough to contain VLRs. Data offset is ";
363
// oss << m_header.GetDataOffset() << " while the required total size ";
364
// oss << "for the VLRs is " << GetRequiredHeaderSize();
365
// throw std::runtime_error(oss.str());
368
for (uint32_t i = 0; i < m_header.GetRecordsCount(); ++i)
370
VariableRecord const &vlr = m_header.GetVLR(i);
372
detail::write_n(m_ofs, vlr.GetReserved(), sizeof(uint16_t));
373
detail::write_n(m_ofs, vlr.GetUserId(true).c_str(), 16);
374
detail::write_n(m_ofs, vlr.GetRecordId(), sizeof(uint16_t));
375
detail::write_n(m_ofs, vlr.GetRecordLength(), sizeof(uint16_t));
376
detail::write_n(m_ofs, vlr.GetDescription(true).c_str(), 32);
377
std::vector<uint8_t> const& data = vlr.GetData();
378
std::streamsize const size = static_cast<std::streamsize>(data.size());
379
detail::write_n(m_ofs, data.front(), size);
386
boost::int32_t Header::GetRequiredHeaderSize() const
388
return m_header.GetVLRBlockSize() + m_header.GetHeaderSize();
391
void Header::WriteLAS10PadSignature()
393
// Only write pad signature bytes for LAS 1.0 files. Any other files
394
// will not get the pad bytes and we are *not* allowing anyone to
395
// override this either - hobu
397
if (m_header.GetVersionMinor() > 0) {
401
int32_t diff = m_header.GetDataOffset() - GetRequiredHeaderSize();
405
m_header.SetDataOffset(m_header.GetDataOffset() + 2);
406
// Seek to the location of the data offset in the header and write a new one.
407
m_ofs.seekp(96, std::ios::beg);
408
detail::write_n(m_ofs, m_header.GetDataOffset(), sizeof(m_header.GetDataOffset()));
412
// step back two bytes to write the pad bytes. We should have already
413
// determined by this point if a) they will fit b) they won't overwrite
415
m_ofs.seekp(m_header.GetDataOffset() - 2, std::ios::beg);
417
// Write the pad bytes.
418
uint8_t const sgn1 = 0xCC;
419
uint8_t const sgn2 = 0xDD;
420
detail::write_n(m_ofs, sgn1, sizeof(uint8_t));
421
detail::write_n(m_ofs, sgn2, sizeof(uint8_t));
425
}}} // namespace liblas::detail::writer