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 
28 using namespace Debug;
29 
30 namespace OpenRaw {
31 namespace Internals {
32 
33 namespace CIFF {
34 
35 
36 bool 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.unwrap();
46  result_u32 = container->readUInt32(file);
47  if (result_u32.empty()) {
48  return false;
49  }
50  imageHeight = result_u32.unwrap();
51  result_u32 = container->readUInt32(file);
52  if (result_u32.empty()) {
53  return false;
54  }
55  pixelAspectRatio = result_u32.unwrap();
56  auto result_32 = container->readInt32(file);
57  if (result_32.empty()) {
58  return false;
59  }
60  rotationAngle = result_32.unwrap();
61  result_u32 = container->readUInt32(file);
62  if (result_u32.empty()) {
63  return false;
64  }
65  componentBitDepth = result_u32.unwrap();
66  result_u32 = container->readUInt32(file);
67  if (result_u32.empty()) {
68  return false;
69  }
70  colorBitDepth = result_u32.unwrap();
71  result_u32 = container->readUInt32(file);
72  if (result_u32.empty()) {
73  return false;
74  }
75  colorBW = result_u32.unwrap();
76  return true;
77 }
78 
79 int32_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 
99 RecordEntry::RecordEntry()
100  : typeCode(0), length(0), offset(0)
101 {
102 }
103 
104 bool RecordEntry::readFrom(CIFFContainer *container)
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.unwrap();
112  auto result_32 = container->readUInt32(file);
113  if (result_32.empty()) {
114  return false;
115  }
116  length = result_32.unwrap();
117  result_32 = container->readUInt32(file);
118  if (result_32.empty()) {
119  return false;
120  }
121  offset = result_32.unwrap();
122  return true;
123 }
124 
125 size_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 
132 Heap::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 @ %ld length = %ld\n", start, m_length);
139 }
140 
141 std::vector<RecordEntry> & Heap::records()
142 {
143  if (m_records.size() == 0) {
144  _loadRecords();
145  }
146  return m_records;
147 }
148 
149 
150 bool 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.ok()) {
158  int32_t record_offset = result.unwrap();
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.unwrap();
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
182 class OffsetTable {
183  uint16_t numRecords;/* the number tblArray elements */
184  RecordEntry tblArray[1];/* Array of the record entries */
185 };
186 #endif
187 
188 
189 bool 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')) {
200  endian = RawContainer::ENDIAN_BIG;
201  }
202  container->setEndian(endian);
203  auto result32 = container->readUInt32(file);
204  if (result32.ok()) {
205  headerLength = result32.unwrap();
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.ok()) {
217  version = result32.unwrap();
218  ret = true;
219  }
220  }
221  }
222  return ret;
223 }
224 
225 }
226 
227 CIFFContainer::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 
236 CIFFContainer::~CIFFContainer()
237 {
238 }
239 
240 CIFF::Heap::Ref CIFFContainer::heap()
241 {
242  if (m_heap == nullptr) {
243  _loadHeap();
244  }
245  return m_heap;
246 }
247 
248 bool 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 %ld\n", 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 
271 RawContainer::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 
282 CIFF::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 
307 const 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 
330 const 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 
353 const 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 */
size_t fetchData(void *buf, off_t offset, size_t buf_size)
CIFF is the container for CRW files. It is an attempt from Canon to make this a standard. I guess it failed.
Definition: arwfile.cpp:30
Option< int16_t > readInt16(const IO::Stream::Ptr &f)
Option< uint32_t > readUInt32(const IO::Stream::Ptr &f)
Definition: trace.cpp:30
Option< uint16_t > readUInt16(const IO::Stream::Ptr &f)
Option< int32_t > readInt32(const IO::Stream::Ptr &f)