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