libopenraw
ciffcontainer.cpp
1/*
2 * libopenraw - ciffcontainer.cpp
3 *
4 * Copyright (C) 2006-2017 Hubert Figuière
5 *
6 * This library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public License
8 * as published by the Free Software Foundation, either version 3 of
9 * the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21#include <fcntl.h>
22#include <algorithm>
23#include <cstring>
24
25#include "ciffcontainer.hpp"
26#include "trace.hpp"
27
28using namespace Debug;
29
30namespace OpenRaw {
31namespace Internals {
32
33namespace CIFF {
34
35
36bool ImageSpec::readFrom(off_t offset, CIFFContainer *container)
37{
38 auto file = container->file();
39 file->seek(offset, SEEK_SET);
40
41 auto result_u32 = container->readUInt32(file);
42 if (result_u32.empty()) {
43 return false;
44 }
45 imageWidth = result_u32.value();
46 result_u32 = container->readUInt32(file);
47 if (result_u32.empty()) {
48 return false;
49 }
50 imageHeight = result_u32.value();
51 result_u32 = container->readUInt32(file);
52 if (result_u32.empty()) {
53 return false;
54 }
55 pixelAspectRatio = result_u32.value();
56 auto result_32 = container->readInt32(file);
57 if (result_32.empty()) {
58 return false;
59 }
60 rotationAngle = result_32.value();
61 result_u32 = container->readUInt32(file);
62 if (result_u32.empty()) {
63 return false;
64 }
65 componentBitDepth = result_u32.value();
66 result_u32 = container->readUInt32(file);
67 if (result_u32.empty()) {
68 return false;
69 }
70 colorBitDepth = result_u32.value();
71 result_u32 = container->readUInt32(file);
72 if (result_u32.empty()) {
73 return false;
74 }
75 colorBW = result_u32.value();
76 return true;
77}
78
79int32_t ImageSpec::exifOrientation() const
80{
81 int32_t orientation = 0;
82 switch(rotationAngle) {
83 case 0:
84 orientation = 1;
85 break;
86 case 90:
87 orientation = 6;
88 break;
89 case 180:
90 orientation = 3;
91 break;
92 case 270:
93 orientation = 8;
94 break;
95 }
96 return orientation;
97}
98
99RecordEntry::RecordEntry()
100 : typeCode(0), length(0), offset(0)
101{
102}
103
105{
106 auto file = container->file();
107 auto result_16 = container->readUInt16(file);
108 if (result_16.empty()) {
109 return false;
110 }
111 typeCode = result_16.value();
112 auto result_32 = container->readUInt32(file);
113 if (result_32.empty()) {
114 return false;
115 }
116 length = result_32.value();
117 result_32 = container->readUInt32(file);
118 if (result_32.empty()) {
119 return false;
120 }
121 offset = result_32.value();
122 return true;
123}
124
125size_t RecordEntry::fetchData(Heap* heap, void* buf, size_t size) const
126{
127 return heap->container()->fetchData(buf,
128 offset + heap->offset(), size);
129}
130
131
132Heap::Heap(off_t start, off_t length, CIFFContainer * _container)
133 : m_start(start),
134 m_length(length),
135 m_container(_container),
136 m_records()
137{
138 LOGDBG2("Heap @ %lld length = %lld\n", (long long int)start, (long long int)m_length);
139}
140
141std::vector<RecordEntry> & Heap::records()
142{
143 if (m_records.size() == 0) {
144 _loadRecords();
145 }
146 return m_records;
147}
148
149
150bool Heap::_loadRecords()
151{
152 auto file = m_container->file();
153 file->seek(m_start + m_length - 4, SEEK_SET);
154
155 auto result = m_container->readInt32(file);
156
157 if (result) {
158 int32_t record_offset = result.value();
159
160 m_records.clear();
161 file->seek(m_start + record_offset, SEEK_SET);
162 auto result16 = m_container->readInt16(file);
163 if (result16.empty()) {
164 LOGDBG1("read numRecords failed\n");
165 return false;
166 }
167 int16_t numRecords = result16.value();
168 LOGDBG2("numRecords %d\n", numRecords);
169
170 m_records.reserve(numRecords);
171 for (int16_t i = 0; i < numRecords; i++) {
172 m_records.push_back(RecordEntry());
173 m_records.back().readFrom(m_container);
174 }
175 return true;
176 }
177 return false;
178}
179
180
181#if 0
182class OffsetTable {
183 uint16_t numRecords;/* the number tblArray elements */
184 RecordEntry tblArray[1];/* Array of the record entries */
185};
186#endif
187
188
189bool HeapFileHeader::readFrom(CIFFContainer *container)
190{
191 endian = RawContainer::ENDIAN_NULL;
192 bool ret = false;
193 auto file = container->file();
194 int s = file->read(byteOrder, 2);
195 if (s == 2) {
196 if((byteOrder[0] == 'I') && (byteOrder[1] == 'I')) {
198 }
199 else if((byteOrder[0] == 'M') && (byteOrder[1] == 'M')) {
201 }
202 container->setEndian(endian);
203 auto result32 = container->readUInt32(file);
204 if (result32) {
205 headerLength = result32.value();
206 ret = true;
207 }
208 if (ret) {
209 ret = (file->read(type, 4) == 4);
210 }
211 if (ret) {
212 ret = (file->read(subType, 4) == 4);
213 }
214 if (ret) {
215 result32 = container->readUInt32(file);
216 if (result32) {
217 version = result32.value();
218 ret = true;
219 }
220 }
221 }
222 return ret;
223}
224
225}
226
227CIFFContainer::CIFFContainer(const IO::Stream::Ptr &_file)
228 : RawContainer(_file, 0),
229 m_hdr(),
230 m_heap(nullptr),
231 m_hasImageSpec(false)
232{
233 m_endian = _readHeader();
234}
235
236CIFFContainer::~CIFFContainer()
237{
238}
239
240CIFF::Heap::Ref CIFFContainer::heap()
241{
242 if (m_heap == nullptr) {
243 _loadHeap();
244 }
245 return m_heap;
246}
247
248bool CIFFContainer::_loadHeap()
249{
250 bool ret = false;
251 if (m_heap) {
252 return false;
253 }
254 if (m_endian != ENDIAN_NULL) {
255 off_t heapLength = m_file->filesize() - m_hdr.headerLength;
256
257 LOGDBG1("heap len %lld\n", (long long int)heapLength);
258 m_heap = std::make_shared<CIFF::Heap>(m_hdr.headerLength,
259 heapLength, this);
260
261 ret = true;
262 }
263 else {
264 LOGDBG1("Unknown endian\n");
265 }
266
267 return ret;
268}
269
270
271RawContainer::EndianType CIFFContainer::_readHeader()
272{
273 EndianType _endian = ENDIAN_NULL;
274 m_hdr.readFrom(this);
275 if ((::strncmp(m_hdr.type, "HEAP", 4) == 0)
276 && (::strncmp(m_hdr.subType, "CCDR", 4) == 0)) {
277 _endian = m_hdr.endian;
278 }
279 return _endian;
280}
281
282CIFF::Heap::Ref CIFFContainer::getImageProps()
283{
284 if(!m_imageprops) {
285 if(!heap()) {
286 return CIFF::Heap::Ref();
287 }
288
289 auto & records = m_heap->records();
290
291 // locate the properties
292 auto iter = std::find_if(records.cbegin(), records.cend(),
293 [](const CIFF::RecordEntry& e) {
294 return e.isA(static_cast<uint16_t>(CIFF::TAG_IMAGEPROPS));
295 });
296 if (iter == records.end()) {
297 LOGERR("Couldn't find the image properties.\n");
298 return CIFF::Heap::Ref();
299 }
300
301 m_imageprops = std::make_shared<CIFF::Heap>(
302 iter->offset + m_heap->offset(), iter->length, this);
303 }
304 return m_imageprops;
305}
306
307const CIFF::ImageSpec * CIFFContainer::getImageSpec()
308{
309 if(!m_hasImageSpec) {
310 CIFF::Heap::Ref props = getImageProps();
311
312 if(!props) {
313 return nullptr;
314 }
315 auto & propsRecs = props->records();
316 auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
317 [] (const CIFF::RecordEntry &e) {
318 return e.isA(static_cast<uint16_t>(CIFF::TAG_IMAGEINFO));
319 });
320 if (iter == propsRecs.end()) {
321 LOGERR("Couldn't find the image info.\n");
322 return nullptr;
323 }
324 m_imagespec.readFrom(iter->offset + props->offset(), this);
325 m_hasImageSpec = true;
326 }
327 return &m_imagespec;
328}
329
330const CIFF::Heap::Ref CIFFContainer::getCameraProps()
331{
332 if(!m_cameraprops) {
333 CIFF::Heap::Ref props = getImageProps();
334
335 if(!props) {
336 return CIFF::Heap::Ref();
337 }
338 auto & propsRecs = props->records();
339 auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
340 [] (const CIFF::RecordEntry & e) {
341 return e.isA(static_cast<uint16_t>(CIFF::TAG_CAMERAOBJECT));
342 });
343 if (iter == propsRecs.end()) {
344 LOGERR("Couldn't find the camera props.\n");
345 return CIFF::Heap::Ref();
346 }
347 m_cameraprops = std::make_shared<CIFF::Heap>(
348 iter->offset + props->offset(), iter->length, this);
349 }
350 return m_cameraprops;
351}
352
353const CIFF::RecordEntry * CIFFContainer::getRawDataRecord() const
354{
355 if(!m_heap) {
356 return nullptr;
357 }
358 auto & records = m_heap->records();
359 // locate the RAW data
360 auto iter = std::find_if(records.cbegin(), records.cend(),
361 [] (const CIFF::RecordEntry &e) {
362 return e.isA(static_cast<uint16_t>(CIFF::TAG_RAWIMAGEDATA));
363 });
364
365 if (iter != records.end()) {
366 return &(*iter);
367 }
368 return nullptr;
369}
370
371}
372}
373/*
374 Local Variables:
375 mode:c++
376 c-file-style:"stroustrup"
377 c-file-offsets:((innamespace . 0))
378 indent-tabs-mode:nil
379 fill-column:80
380 End:
381*/
Heap(off_t start, off_t length, CIFFContainer *container)
bool readFrom(off_t offset, CIFFContainer *container)
bool readFrom(CIFFContainer *container)
size_t fetchData(Heap *heap, void *buf, size_t size) const
Option< int16_t > readInt16(const IO::Stream::Ptr &f)
size_t fetchData(void *buf, off_t offset, size_t buf_size)
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f)
Option< uint32_t > readUInt32(const IO::Stream::Ptr &f)
Option< int32_t > readInt32(const IO::Stream::Ptr &f)
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard....
Definition arwfile.cpp:30