libopenraw
ciffcontainer.cpp
1 /*
2  * libopenraw - ciffcontainer.cpp
3  *
4  * Copyright (C) 2006-2016 Hubert Figuiere
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  bool ret;
39  auto file = container->file();
40  file->seek(offset, SEEK_SET);
41  ret = container->readUInt32(file, imageWidth);
42  ret = container->readUInt32(file, imageHeight);
43  ret = container->readUInt32(file, pixelAspectRatio);
44  ret = container->readInt32(file, rotationAngle);
45  ret = container->readUInt32(file, componentBitDepth);
46  ret = container->readUInt32(file, colorBitDepth);
47  ret = container->readUInt32(file, colorBW);
48  return ret;
49 }
50 
51 int32_t ImageSpec::exifOrientation() const
52 {
53  int32_t orientation = 0;
54  switch(rotationAngle) {
55  case 0:
56  orientation = 1;
57  break;
58  case 90:
59  orientation = 6;
60  break;
61  case 180:
62  orientation = 3;
63  break;
64  case 270:
65  orientation = 8;
66  break;
67  }
68  return orientation;
69 }
70 
71 RecordEntry::RecordEntry()
72  : typeCode(0), length(0), offset(0)
73 {
74 }
75 
76 bool RecordEntry::readFrom(CIFFContainer *container)
77 {
78  bool ret;
79  auto file = container->file();
80  ret = container->readUInt16(file, typeCode);
81  ret = container->readUInt32(file, length);
82  ret = container->readUInt32(file, offset);
83  return ret;
84 }
85 
86 size_t RecordEntry::fetchData(Heap* heap, void* buf, size_t size) const
87 {
88  return heap->container()->fetchData(buf,
89  offset + heap->offset(), size);
90 }
91 
92 
93 Heap::Heap(off_t start, off_t length, CIFFContainer * _container)
94  : m_start(start),
95  m_length(length),
96  m_container(_container),
97  m_records()
98 {
99  Debug::Trace(DEBUG2) << "Heap @ " << start << " length = "
100  << m_length << "\n";
101 }
102 
103 std::vector<RecordEntry> & Heap::records()
104 {
105  if (m_records.size() == 0) {
106  _loadRecords();
107  }
108  return m_records;
109 }
110 
111 
112 bool Heap::_loadRecords()
113 {
114  auto file = m_container->file();
115  file->seek(m_start + m_length - 4, SEEK_SET);
116  int32_t record_offset;
117  bool ret = m_container->readInt32(file, record_offset);
118 
119  if (ret) {
120  int16_t numRecords;
121 
122  m_records.clear();
123  file->seek(m_start + record_offset, SEEK_SET);
124  ret = m_container->readInt16(file, numRecords);
125  if (!ret) {
126  Trace(DEBUG1) << "read failed: " << ret << "\n";
127  }
128  Trace(DEBUG2) << "numRecords " << numRecords << "\n";
129  int16_t i;
130  m_records.reserve(numRecords);
131  for (i = 0; i < numRecords; i++) {
132  m_records.push_back(RecordEntry());
133  m_records.back().readFrom(m_container);
134  }
135  }
136  return ret;
137 }
138 
139 
140 #if 0
141 class OffsetTable {
142  uint16_t numRecords;/* the number tblArray elements */
143  RecordEntry tblArray[1];/* Array of the record entries */
144 };
145 #endif
146 
147 
148 bool HeapFileHeader::readFrom(CIFFContainer *container)
149 {
150  endian = RawContainer::ENDIAN_NULL;
151  bool ret = false;
152  auto file = container->file();
153  int s = file->read(byteOrder, 2);
154  if (s == 2) {
155  if((byteOrder[0] == 'I') && (byteOrder[1] == 'I')) {
157  }
158  else if((byteOrder[0] == 'M') && (byteOrder[1] == 'M')) {
159  endian = RawContainer::ENDIAN_BIG;
160  }
161  container->setEndian(endian);
162  ret = container->readUInt32(file, headerLength);
163  if (ret) {
164  ret = (file->read(type, 4) == 4);
165  }
166  if (ret) {
167  ret = (file->read(subType, 4) == 4);
168  }
169  if (ret) {
170  ret = container->readUInt32(file, version);
171  }
172  }
173  return ret;
174 }
175 
176 }
177 
178 CIFFContainer::CIFFContainer(const IO::Stream::Ptr &_file)
179  : RawContainer(_file, 0),
180  m_hdr(),
181  m_heap(nullptr),
182  m_hasImageSpec(false)
183 {
184  m_endian = _readHeader();
185 }
186 
187 CIFFContainer::~CIFFContainer()
188 {
189 }
190 
191 CIFF::Heap::Ref CIFFContainer::heap()
192 {
193  if (m_heap == nullptr) {
194  _loadHeap();
195  }
196  return m_heap;
197 }
198 
199 bool CIFFContainer::_loadHeap()
200 {
201  bool ret = false;
202  if (m_heap) {
203  return false;
204  }
205  if (m_endian != ENDIAN_NULL) {
206  off_t heapLength = m_file->filesize() - m_hdr.headerLength;
207 
208  Trace(DEBUG1) << "heap len " << heapLength << "\n";
209  m_heap = std::make_shared<CIFF::Heap>(m_hdr.headerLength,
210  heapLength, this);
211 
212  ret = true;
213  }
214  else {
215  Trace(DEBUG1) << "Unknown endian\n";
216  }
217 
218  return ret;
219 }
220 
221 
222 RawContainer::EndianType CIFFContainer::_readHeader()
223 {
224  EndianType _endian = ENDIAN_NULL;
225  m_hdr.readFrom(this);
226  if ((::strncmp(m_hdr.type, "HEAP", 4) == 0)
227  && (::strncmp(m_hdr.subType, "CCDR", 4) == 0)) {
228  _endian = m_hdr.endian;
229  }
230  return _endian;
231 }
232 
233 CIFF::Heap::Ref CIFFContainer::getImageProps()
234 {
235  if(!m_imageprops) {
236  if(!heap()) {
237  return CIFF::Heap::Ref();
238  }
239 
240  auto & records = m_heap->records();
241 
242  // locate the properties
243  auto iter = std::find_if(records.cbegin(), records.cend(),
244  [](const CIFF::RecordEntry& e) {
245  return e.isA(static_cast<uint16_t>(CIFF::TAG_IMAGEPROPS));
246  });
247  if (iter == records.end()) {
248  Trace(ERROR) << "Couldn't find the image properties.\n";
249  return CIFF::Heap::Ref();
250  }
251 
252  m_imageprops = std::make_shared<CIFF::Heap>(
253  iter->offset + m_heap->offset(), iter->length, this);
254  }
255  return m_imageprops;
256 }
257 
258 const CIFF::ImageSpec * CIFFContainer::getImageSpec()
259 {
260  if(!m_hasImageSpec) {
261  CIFF::Heap::Ref props = getImageProps();
262 
263  if(!props) {
264  return nullptr;
265  }
266  auto & propsRecs = props->records();
267  auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
268  [] (const CIFF::RecordEntry &e) {
269  return e.isA(static_cast<uint16_t>(CIFF::TAG_IMAGEINFO));
270  });
271  if (iter == propsRecs.end()) {
272  Trace(ERROR) << "Couldn't find the image info.\n";
273  return nullptr;
274  }
275  m_imagespec.readFrom(iter->offset + props->offset(), this);
276  m_hasImageSpec = true;
277  }
278  return &m_imagespec;
279 }
280 
281 const CIFF::Heap::Ref CIFFContainer::getCameraProps()
282 {
283  if(!m_cameraprops) {
284  CIFF::Heap::Ref props = getImageProps();
285 
286  if(!props) {
287  return CIFF::Heap::Ref();
288  }
289  auto & propsRecs = props->records();
290  auto iter = std::find_if(propsRecs.cbegin(), propsRecs.cend(),
291  [] (const CIFF::RecordEntry & e) {
292  return e.isA(static_cast<uint16_t>(CIFF::TAG_CAMERAOBJECT));
293  });
294  if (iter == propsRecs.end()) {
295  Trace(ERROR) << "Couldn't find the camera props.\n";
296  return CIFF::Heap::Ref();
297  }
298  m_cameraprops = std::make_shared<CIFF::Heap>(
299  iter->offset + props->offset(), iter->length, this);
300  }
301  return m_cameraprops;
302 }
303 
304 const CIFF::RecordEntry * CIFFContainer::getRawDataRecord() const
305 {
306  if(!m_heap) {
307  return nullptr;
308  }
309  auto & records = m_heap->records();
310  // locate the RAW data
311  auto iter = std::find_if(records.cbegin(), records.cend(),
312  [] (const CIFF::RecordEntry &e) {
313  return e.isA(static_cast<uint16_t>(CIFF::TAG_RAWIMAGEDATA));
314  });
315 
316  if (iter != records.end()) {
317  return &(*iter);
318  }
319  return nullptr;
320 }
321 
322 }
323 }
324 /*
325  Local Variables:
326  mode:c++
327  c-file-style:"stroustrup"
328  c-file-offsets:((innamespace . 0))
329  indent-tabs-mode:nil
330  fill-column:80
331  End:
332 */
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
bool readUInt32(const IO::Stream::Ptr &f, uint32_t &v)
Definition: trace.cpp:30
bool readUInt16(const IO::Stream::Ptr &f, uint16_t &v)
bool readInt32(const IO::Stream::Ptr &f, int32_t &v)
bool readInt16(const IO::Stream::Ptr &f, int16_t &v)