libopenraw
mrwcontainer.cpp
00001 /*
00002  * libopenraw - mrwcontainer.cpp
00003  *
00004  * Copyright (C) 2006 Hubert Figuiere
00005  * Copyright (C) 2008 Bradley Broom
00006  *
00007  * This library is free software: you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation, either version 3 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Lesser General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this library.  If not, see
00019  * <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 #include "trace.h"
00023 #include "mrwcontainer.h"
00024 #include "io/file.h"
00025 
00026 
00027 using namespace Debug;
00028 
00029 namespace OpenRaw {
00030 
00031     namespace Internals {
00032 
00033         namespace MRW {
00034 
00035             DataBlock::DataBlock(off_t start, MRWContainer * _container)
00036                 : m_start(start),
00037                   m_container(_container),
00038                   m_loaded(false)
00039             {
00040                 Trace(DEBUG2) << "> DataBlock start == " << start << "\n";
00041                 if (m_container->fetchData (m_name, m_start, 4) != 4) {
00042                     // FIXME: Handle error
00043                     Trace(WARNING) << "  Error reading block name " << start << "\n";
00044                     return;
00045                 }
00046                 if (!m_container->readInt32 (m_container->file(), m_length)) {
00047                     // FIXME: Handle error
00048                     Trace(WARNING) << "  Error reading block length " << start << "\n";
00049                     return;
00050                 }
00051                 Trace(DEBUG1) << "  DataBlock " << name() 
00052                               << ", length " << m_length 
00053                               << " at " << m_start << "\n";
00054                 Trace(DEBUG2) << "< DataBlock\n";
00055                 m_loaded = true;
00056             }
00057 
00058             int8_t DataBlock::int8_val (off_t off)
00059             {
00060                 int8_t ret;
00061                 MRWContainer *mc = m_container;
00062                 mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
00063                 mc->readInt8 (mc->file(), ret);
00064                 return ret;
00065             }
00066             
00067             uint8_t DataBlock::uint8_val (off_t off)
00068             {
00069                 uint8_t ret;
00070                 MRWContainer *mc = m_container;
00071                 mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
00072                 mc->readUInt8 (mc->file(), ret);
00073                 return ret;
00074             }
00075             
00076             uint16_t DataBlock::uint16_val (off_t off)
00077             {
00078                 uint16_t ret;
00079                 MRWContainer *mc = m_container;
00080                 mc->file()->seek (m_start + DataBlockHeaderLength + off, SEEK_SET);
00081                 mc->readUInt16 (mc->file(), ret);
00082                 return ret;
00083             }
00084             
00085             std::string DataBlock::string_val(off_t off)
00086             {
00087                 char buf[9];
00088                 size_t s;
00089                 MRWContainer *mc = m_container;
00090                 s = mc->fetchData(buf, m_start + DataBlockHeaderLength + off, 8);
00091                 if(s == 8) {
00092                     buf[8] = 0;
00093                 }
00094                 else {
00095                     *buf = 0;
00096                 }
00097                 return buf;
00098             }
00099         }
00100 
00101         MRWContainer::MRWContainer(IO::Stream *_file, off_t offset)
00102             : IFDFileContainer(_file, offset)
00103         {
00104 
00105         }
00106 
00107 
00108         MRWContainer::~MRWContainer()
00109         {
00110         }
00111 
00112 
00113         IFDFileContainer::EndianType 
00114         MRWContainer::isMagicHeader(const char *p, int len)
00115         {
00116             if (len < 4) {
00117                 // we need at least 4 bytes to check
00118                 return ENDIAN_NULL;
00119             }
00120 
00121             if ((p[0] == 0x00) && (p[1] == 'M') && 
00122                 (p[2] == 'R') && (p[3] == 'M')) {
00123 
00124                 Trace(DEBUG1) << "Identified MRW file\n";
00125 
00126                 return ENDIAN_BIG;
00127             }
00128 
00129             Trace(DEBUG1) << "Unidentified MRW file\n";
00130 
00131             return ENDIAN_NULL;
00132         }
00133 
00134         bool MRWContainer::locateDirsPreHook()
00135         {
00136             char version[9];
00137             off_t position;
00138 
00139             Trace(DEBUG1) << "> MRWContainer::locateDirsPreHook()\n";
00140             m_endian = ENDIAN_BIG;
00141             
00142             /* MRW file always starts with an MRM datablock. */
00143             mrm = MRW::DataBlock::Ref (new MRW::DataBlock (m_offset, this));
00144             if (mrm->name() != "MRM") {
00145                 Trace(WARNING) << "MRW file begins not with MRM block, "
00146                     "but with unrecognized DataBlock :: name == " 
00147                                << mrm->name() << "\n";
00148                 return false;
00149             }
00150 
00151             /* Subblocks are contained within the MRM block. Scan them and create
00152              * appropriate block descriptors.
00153              */
00154             position = mrm->offset() + MRW::DataBlockHeaderLength;
00155             while (position < pixelDataOffset()) {
00156                 MRW::DataBlock::Ref ref (new MRW::DataBlock (position, this));
00157                 Trace(DEBUG1) << "Loaded DataBlock :: name == " << ref->name() << "\n";
00158                 if(!ref || !ref->loaded()) {
00159                     break;
00160                 }
00161                 if (ref->name() == "PRD") {
00162                     if (prd != NULL) {
00163                         Trace(WARNING) << "File contains duplicate DataBlock :: name == " 
00164                                        << ref->name() << "\n";
00165                     }
00166                     prd = ref;
00167                 }
00168                 else if (ref->name() == "TTW") {
00169                     if (ttw != NULL) {
00170                         Trace(WARNING) << "File contains duplicate DataBlock :: name == " 
00171                                        << ref->name() << "\n";
00172                     }
00173                     ttw = ref;
00174                 }
00175                 else if (ref->name() == "WBG") {
00176                     if (wbg != NULL) {
00177                         Trace(WARNING) << "File contains duplicate DataBlock :: name == " 
00178                                        << ref->name() << "\n";
00179                     }
00180                     wbg = ref;
00181                 }
00182                 else if (ref->name() == "RIF") {
00183                     if (rif != NULL) {
00184                         Trace(WARNING) << "File contains duplicate DataBlock :: name == " 
00185                                        << ref->name() << "\n";
00186                     }
00187                     rif = ref;
00188                 }
00189                 else if (ref->name() != "PAD") {
00190                     Trace(WARNING) << "File contains unrecognized DataBlock :: name == " 
00191                                    << ref->name() << "\n";
00192                 }
00193                 position = ref->offset() + MRW::DataBlockHeaderLength + ref->length();
00194             }
00195 
00196             /* Check that we found all the expected data blocks. */
00197             if (prd == NULL) {
00198                 Trace(WARNING) << "File does NOT contain expected DataBlock :: name == PRD\n";
00199                 return false;
00200             }
00201             if (ttw == NULL) {
00202                 Trace(WARNING) << "File does NOT contain expected DataBlock :: name == TTW\n";
00203                 return false;
00204             }
00205             if (wbg == NULL) {
00206                 Trace(WARNING) << "File does NOT contain expected DataBlock :: name == WBG\n";
00207                 return false;
00208             }
00209             if (rif == NULL) {
00210                 Trace(WARNING) << "File does NOT contain expected DataBlock :: name == RIF\n";
00211                 return false;
00212             }
00213 
00214             /* Extract the file version string. */
00215             if (fetchData (version, prd->offset()+MRW::DataBlockHeaderLength+MRW::PRD_VERSION, 8) != 8) {
00216                 // FIXME: Handle error
00217                 Debug::Trace(DEBUG1) << "  Error reading version string\n";
00218             }
00219             version[8] = '\0';
00220             m_version = std::string (version);
00221             Trace(DEBUG1) << "  MRW file version == " << m_version << "\n";
00222 
00223             /* For the benefit of our parent class, set the container offset to the beginning of
00224              * the TIFF data (the contents of the TTW data block), and seek there.
00225              */
00226             m_offset = ttw->offset() + MRW::DataBlockHeaderLength;
00227             if((version[2] != '7') || (version[3] != '3')) {
00228                 setExifOffsetCorrection(m_offset);
00229                 Trace(DEBUG1) << "setting correction to " << m_offset << "\n";
00230             }
00231             m_file->seek (m_offset, SEEK_SET);
00232             Trace(DEBUG1) << "< MRWContainer\n";
00233             
00234             return true;
00235         }
00236 
00237     }
00238 }