ifdfilecontainer.cpp

00001 /*
00002  * libopenraw - ifdfilecontainer.cpp
00003  *
00004  * Copyright (C) 2006 Hubert Figuiere
00005  *
00006  * This library is free software: you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public License
00008  * as published by the Free Software Foundation, either version 3 of
00009  * the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library.  If not, see
00018  * <http://www.gnu.org/licenses/>.
00019  */
00020 
00021 #include <sys/types.h>
00022 
00023 #include <cstdlib>
00024 #include <cstdio>
00025 #include <vector>
00026 #include <iostream>
00027 
00028 #include "debug.h"
00029 
00030 #include "ifdfilecontainer.h"
00031 #include "io/file.h"
00032 
00033 
00034 using namespace Debug;
00035 
00036 namespace OpenRaw {
00037 
00038     namespace Internals {
00039 
00040         IFDFileContainer::IFDFileContainer(IO::Stream *_file, off_t offset)
00041             : RawContainer(_file, offset), 
00042               m_error(0),
00043               m_exif_offset_correction(0),
00044               m_current_dir(),
00045               m_dirs()
00046         {
00047         }
00048     
00049         IFDFileContainer::~IFDFileContainer()
00050         {
00051             m_dirs.clear();
00052         }
00053 
00054 
00055         IFDFileContainer::EndianType 
00056         IFDFileContainer::isMagicHeader(const char *p, int len)
00057         {
00058             if (len < 4){
00059                 // we need at least 4 bytes to check
00060                 return ENDIAN_NULL;
00061             }
00062             if ((p[0] == 0x49) && (p[1] == 0x49)
00063                     && (p[2] == 0x2a) && (p[3] == 0x00)) {
00064                 return ENDIAN_LITTLE;
00065             }
00066             else if ((p[0] == 0x4d) && (p[1] == 0x4d)
00067                              && (p[2] == 0x00) && (p[3] == 0x2a)) {
00068                 return ENDIAN_BIG;
00069             }
00070             return ENDIAN_NULL;
00071         }
00072 
00073 
00074         int IFDFileContainer::countDirectories(void)
00075         {
00076             if (m_dirs.size() == 0) {
00077                 // FIXME check result
00078                 bool ret = _locateDirs();
00079                 if (!ret) {
00080                     return -1;
00081                 }
00082             }
00083             return m_dirs.size();
00084         }
00085 
00086         std::vector<IFDDir::Ref> & 
00087         IFDFileContainer::directories()
00088         {
00089             if (m_dirs.size() == 0) {
00090                 countDirectories();
00091             }
00092             return m_dirs;
00093         }
00094 
00095         IFDDir::Ref
00096         IFDFileContainer::setDirectory(int dir)
00097         {
00098             if (dir < 0) {
00099                 // FIXME set error
00100                 return IFDDir::Ref((IFDDir*)NULL);
00101             }
00102             // FIXME handle negative values
00103             int n = countDirectories();
00104             if (n <= 0) {
00105                 // FIXME set error
00106                 return IFDDir::Ref((IFDDir*)NULL);
00107             }
00108             // dir is signed here because we can pass negative 
00109             // value for specific Exif IFDs.
00110             if (dir > (int)m_dirs.size()) {
00111                 // FIXME set error
00112                 return IFDDir::Ref((IFDDir*)NULL);
00113             }
00114             m_current_dir = m_dirs[dir];
00115             m_current_dir->load();
00116             return m_current_dir;
00117         }
00118 
00119 
00120         size_t 
00121         IFDFileContainer::getDirectoryDataSize()
00122         {
00123             // TODO move to IFDirectory
00124             Trace(DEBUG1) << "getDirectoryDataSize()" << "\n";
00125             off_t offset = m_current_dir->offset();
00126             // FIXME check error
00127             Trace(DEBUG1) << "offset = " << offset 
00128                                 << " m_numTags = " << m_current_dir->numTags() << "\n";
00129             off_t begin = offset + 2 + (m_current_dir->numTags()*12);
00130             
00131             Trace(DEBUG1) << "begin = " << begin << "\n";
00132 
00133             m_file->seek(begin, SEEK_SET);
00134             begin += 2;
00135             int32_t nextIFD;
00136             readInt32(m_file, nextIFD);
00137             Trace(DEBUG1) << "nextIFD = " << nextIFD << "\n";
00138             if (nextIFD == 0) {
00139                 // FIXME not good
00140             }
00141             return nextIFD - begin;
00142         }
00143 
00144         bool IFDFileContainer::locateDirsPreHook() 
00145         { 
00146             return true;
00147         }
00148 
00149 
00150         bool
00151         IFDFileContainer::_locateDirs(void)
00152         {
00153             if(!locateDirsPreHook()) {
00154                 return false;
00155             }
00156             Trace(DEBUG1) << "_locateDirs()\n";
00157             if (m_endian == ENDIAN_NULL) {
00158                 char buf[4];
00159                 m_file->seek(m_offset, SEEK_SET);
00160                 m_file->read(buf, 4);
00161                 m_endian = isMagicHeader(buf, 4);
00162                 if (m_endian == ENDIAN_NULL) {
00163                     // FIXME set error code
00164                     return false;
00165                 }
00166             }
00167             m_file->seek(m_offset + 4, SEEK_SET);
00168             int32_t offset = 0;
00169             readInt32(m_file, offset);
00170             m_dirs.clear();
00171             do {
00172                 if (offset != 0) {
00173 //                  std::cerr.setf(std::ios_base::hex, std::ios_base::basefield);
00174                     Trace(DEBUG1) << "push offset =0x" << offset << "\n";
00175 
00176                     // we assume the offset is relative to the begining of
00177                     // the IFD.
00178                     IFDDir::Ref dir(new IFDDir(m_offset + offset,*this));
00179                     m_dirs.push_back(dir);
00180 
00181 //                  std::cerr.setf((std::ios_base::fmtflags)0, std::ios_base::basefield);
00182 
00183                     offset = dir->nextIFD();
00184                 }
00185             } while(offset != 0);
00186 
00187             Trace(DEBUG1) << "# dir found = " << m_dirs.size() << "\n";
00188             return (m_dirs.size() != 0);
00189         }
00190 
00191 
00192     }
00193 }
00194 

Generated on Sat Aug 15 17:27:04 2009 for libopenraw by  doxygen 1.5.9