00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <cstring>
00022 #include <iostream>
00023 #include <boost/shared_ptr.hpp>
00024
00025 #include <libopenraw/types.h>
00026
00027 #include "io/file.h"
00028 #include "ciffcontainer.h"
00029 #include "debug.h"
00030
00031 using namespace Debug;
00032
00033 namespace OpenRaw {
00034 namespace Internals {
00035
00036 namespace CIFF {
00037
00038
00039 bool ImageSpec::readFrom(off_t offset, CIFFContainer *container)
00040 {
00041 bool ret;
00042 IO::Stream *file = container->file();
00043 file->seek(offset, SEEK_SET);
00044 ret = container->readUInt32(file, imageWidth);
00045 ret = container->readUInt32(file, imageHeight);
00046 ret = container->readUInt32(file, pixelAspectRatio);
00047 ret = container->readInt32(file, rotationAngle);
00048 ret = container->readUInt32(file, componentBitDepth);
00049 ret = container->readUInt32(file, colorBitDepth);
00050 ret = container->readUInt32(file, colorBW);
00051 return ret;
00052 }
00053
00054 int32_t ImageSpec::exifOrientation() const
00055 {
00056 int32_t orientation = 0;
00057 switch(rotationAngle) {
00058 case 0:
00059 orientation = 1;
00060 break;
00061 case 90:
00062 orientation = 6;
00063 break;
00064 case 180:
00065 orientation = 3;
00066 break;
00067 case 270:
00068 orientation = 8;
00069 break;
00070 }
00071 return orientation;
00072 }
00073
00074 RecordEntry::RecordEntry()
00075 : typeCode(0), length(0), offset(0)
00076 {
00077 }
00078
00079 bool RecordEntry::readFrom(CIFFContainer *container)
00080 {
00081 bool ret;
00082 IO::Stream *file = container->file();
00083 ret = container->readUInt16(file, typeCode);
00084 ret = container->readUInt32(file, length);
00085 ret = container->readUInt32(file, offset);
00086 return ret;
00087 }
00088
00089 size_t RecordEntry::fetchData(Heap* heap, void* buf, size_t size) const
00090 {
00091 return heap->container()->fetchData(buf,
00092 offset + heap->offset(), size);
00093 }
00094
00095
00096 Heap::Heap(off_t start, off_t length, CIFFContainer * _container)
00097 : m_start(start),
00098 m_length(length),
00099 m_container(_container),
00100 m_records()
00101 {
00102 Debug::Trace(DEBUG2) << "Heap @ " << start << " length = "
00103 << m_length << "\n";
00104 }
00105
00106 std::vector<RecordEntry> & Heap::records()
00107 {
00108 if (m_records.size() == 0) {
00109 _loadRecords();
00110 }
00111 return m_records;
00112 }
00113
00114
00115 bool Heap::_loadRecords()
00116 {
00117 IO::Stream *file = m_container->file();
00118 file->seek(m_start + m_length - 4, SEEK_SET);
00119 int32_t record_offset;
00120 bool ret = m_container->readInt32(file, record_offset);
00121
00122 if (ret) {
00123 int16_t numRecords;
00124
00125 m_records.clear();
00126 file->seek(m_start + record_offset, SEEK_SET);
00127 ret = m_container->readInt16(file, numRecords);
00128 if (!ret)
00129 {
00130 Trace(DEBUG1) << "read failed: " << ret << "\n";
00131 }
00132 Trace(DEBUG2) << "numRecords " << numRecords << "\n";
00133 int16_t i;
00134 m_records.reserve(numRecords);
00135 for (i = 0; i < numRecords; i++) {
00136 m_records.push_back(RecordEntry());
00137 m_records.back().readFrom(m_container);
00138 }
00139 }
00140 return ret;
00141 }
00142
00143
00144 #if 0
00145 class OffsetTable {
00146 uint16_t numRecords;
00147 RecordEntry tblArray[1];
00148 };
00149 #endif
00150
00151
00152 bool HeapFileHeader::readFrom(CIFFContainer *container)
00153 {
00154 endian = RawContainer::ENDIAN_NULL;
00155 bool ret = false;
00156 IO::Stream *file = container->file();
00157 int s = file->read(byteOrder, 2);
00158 if (s == 2) {
00159 if((byteOrder[0] == 'I') && (byteOrder[1] == 'I')) {
00160 endian = RawContainer::ENDIAN_LITTLE;
00161 }
00162 else if((byteOrder[0] == 'M') && (byteOrder[1] == 'M')) {
00163 endian = RawContainer::ENDIAN_BIG;
00164 }
00165 container->setEndian(endian);
00166 ret = container->readUInt32(file, headerLength);
00167 if (ret) {
00168 ret = (file->read(type, 4) == 4);
00169 }
00170 if (ret) {
00171 ret = (file->read(subType, 4) == 4);
00172 }
00173 if (ret) {
00174 ret = container->readUInt32(file, version);
00175 }
00176 }
00177 return ret;
00178 }
00179 }
00180
00181 CIFFContainer::CIFFContainer(IO::Stream *_file)
00182 : RawContainer(_file, 0),
00183 m_hdr(),
00184 m_heap((CIFF::Heap*)NULL),
00185 m_hasImageSpec(false)
00186 {
00187 m_endian = _readHeader();
00188 }
00189
00190 CIFFContainer::~CIFFContainer()
00191 {
00192 }
00193
00194 CIFF::Heap::Ref CIFFContainer::heap()
00195 {
00196 if (m_heap == NULL) {
00197 _loadHeap();
00198 }
00199 return m_heap;
00200 }
00201
00202 bool CIFFContainer::_loadHeap()
00203 {
00204 bool ret = false;
00205 if (m_heap == NULL) {
00206 if(m_endian != ENDIAN_NULL) {
00207 off_t heapLength = m_file->filesize() - m_hdr.headerLength;
00208
00209 Trace(DEBUG1) << "heap len " << heapLength << "\n";
00210 m_heap = CIFF::Heap::Ref(new CIFF::Heap(m_hdr.headerLength,
00211 heapLength, this));
00212
00213 ret = true;
00214 }
00215 else {
00216 Trace(DEBUG1) << "Unknown endian\n";
00217 }
00218 }
00219 return ret;
00220 }
00221
00222
00223 RawContainer::EndianType CIFFContainer::_readHeader()
00224 {
00225 EndianType _endian = ENDIAN_NULL;
00226 m_hdr.readFrom(this);
00227 if ((::strncmp(m_hdr.type, "HEAP", 4) == 0)
00228 && (::strncmp(m_hdr.subType, "CCDR", 4) == 0)) {
00229 _endian = m_hdr.endian;
00230 }
00231 return _endian;
00232 }
00233
00234 CIFF::Heap::Ref CIFFContainer::getImageProps()
00235 {
00236 if(!m_imageprops) {
00237 if(!heap()) {
00238 return CIFF::Heap::Ref();
00239 }
00240
00241 const CIFF::RecordEntry::List & records = m_heap->records();
00242 CIFF::RecordEntry::List::const_iterator iter;
00243
00244
00245 iter = std::find_if(records.begin(), records.end(), boost::bind(
00246 &CIFF::RecordEntry::isA, _1,
00247 static_cast<uint16_t>(CIFF::TAG_IMAGEPROPS)));
00248 if (iter == records.end()) {
00249 Trace(ERROR) << "Couldn't find the image properties.\n";
00250 return CIFF::Heap::Ref();
00251 }
00252
00253 m_imageprops = CIFF::Heap::Ref(new CIFF::Heap(iter->offset + m_heap->offset(), iter->length, this));
00254 }
00255 return m_imageprops;
00256 }
00257
00258 const CIFF::ImageSpec * CIFFContainer::getImageSpec()
00259 {
00260 if(!m_hasImageSpec) {
00261 CIFF::Heap::Ref props = getImageProps();
00262
00263 if(!props)
00264 return NULL;
00265 const CIFF::RecordEntry::List & propsRecs = props->records();
00266 CIFF::RecordEntry::List::const_iterator iter;
00267 iter = std::find_if(propsRecs.begin(), propsRecs.end(),
00268 boost::bind(
00269 &CIFF::RecordEntry::isA, _1,
00270 static_cast<uint16_t>(CIFF::TAG_IMAGEINFO)));
00271 if (iter == propsRecs.end()) {
00272 Trace(ERROR) << "Couldn't find the image info.\n";
00273 return NULL;
00274 }
00275 m_imagespec.readFrom(iter->offset + props->offset(), this);
00276 m_hasImageSpec = true;
00277 }
00278 return &m_imagespec;
00279 }
00280
00281
00282 const CIFF::Heap::Ref CIFFContainer::getCameraProps()
00283 {
00284 if(!m_cameraprops) {
00285 CIFF::Heap::Ref props = getImageProps();
00286
00287 if(!props)
00288 return CIFF::Heap::Ref();
00289 const CIFF::RecordEntry::List & propsRecs = props->records();
00290 CIFF::RecordEntry::List::const_iterator iter;
00291 iter = std::find_if(propsRecs.begin(), propsRecs.end(),
00292 boost::bind(
00293 &CIFF::RecordEntry::isA, _1,
00294 static_cast<uint16_t>(CIFF::TAG_CAMERAOBJECT)));
00295 if (iter == propsRecs.end()) {
00296 Trace(ERROR) << "Couldn't find the camera props.\n";
00297 return CIFF::Heap::Ref();
00298 }
00299 m_cameraprops = CIFF::Heap::Ref(new CIFF::Heap(iter->offset + props->offset(),
00300 iter->length, this));
00301 }
00302 return m_cameraprops;
00303 }
00304
00305 const CIFF::RecordEntry * CIFFContainer::getRawDataRecord() const
00306 {
00307 if(!m_heap) {
00308 return NULL;
00309 }
00310 const CIFF::RecordEntry::List & records = m_heap->records();
00311 CIFF::RecordEntry::List::const_iterator iter;
00312
00313 iter = std::find_if(records.begin(), records.end(), boost::bind(
00314 &CIFF::RecordEntry::isA, _1,
00315 static_cast<uint16_t>(CIFF::TAG_RAWIMAGEDATA)));
00316
00317 if (iter != records.end()) {
00318 return &(*iter);
00319 }
00320 return NULL;
00321 }
00322 }
00323 }