libopenraw
|
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 "trace.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