/** * @brief Get unsigned short data from raw exif data * This is internal function and is not exposed to client * @param [in] offset Offset to entry in bytes inside raw exif data * @return Unsigned short data */ uint16_t ExifReader::getU16(const size_t offset) const { if (offset + 1 >= m_data.size()) throw ExifParsingError(); if( m_format == INTEL ) { return m_data[offset] + ( m_data[offset + 1] << 8 ); } return ( m_data[offset] << 8 ) + m_data[offset + 1]; }
/** * @brief Get string information from raw exif data * This is internal function and is not exposed to client * @param [in] offset Offset to entry in bytes inside raw exif data * @return string value */ std::string ExifReader::getString(const size_t offset) const { size_t size = getU32( offset + 4 ); size_t dataOffset = 8; // position of data in the field if( size > maxDataSize ) { dataOffset = getU32( offset + 8 ); } if (dataOffset > m_data.size() || dataOffset + size > m_data.size()) { throw ExifParsingError(); } std::vector<uint8_t>::const_iterator it = m_data.begin() + dataOffset; std::string result( it, it + size ); //copy vector content into result return result; }
/** * @brief Get unsigned 32-bit data from raw exif data * This is internal function and is not exposed to client * @param [in] offset Offset to entry in bytes inside raw exif data * @return Unsigned 32-bit data */ uint32_t ExifReader::getU32(const size_t offset) const { if (offset + 3 >= m_data.size()) throw ExifParsingError(); if( m_format == INTEL ) { return m_data[offset] + ( m_data[offset + 1] << 8 ) + ( m_data[offset + 2] << 16 ) + ( m_data[offset + 3] << 24 ); } return ( m_data[offset] << 24 ) + ( m_data[offset + 1] << 16 ) + ( m_data[offset + 2] << 8 ) + m_data[offset + 3]; }
/** * @brief Get exif directory structure contained in file (if any) * This is internal function and is not exposed to client * * @return Map where key is tag number and value is ExifEntry_t structure */ std::map<int, ExifEntry_t > ExifReader::getExif() { const std::streamsize markerSize = 2; const std::streamsize offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header unsigned char appMarker[markerSize]; m_exif.erase( m_exif.begin(), m_exif.end() ); std::streamsize count; bool exifFound = false, stopSearch = false; while( ( !m_stream.eof() ) && !exifFound && !stopSearch ) { m_stream.read( reinterpret_cast<char*>(appMarker), markerSize ); count = m_stream.gcount(); if( count < markerSize ) { break; } unsigned char marker = appMarker[1]; size_t bytesToSkip; size_t exifSize; switch( marker ) { //For all the markers just skip bytes in file pointed by followed two bytes (field size) case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS: case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7: case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8: case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15: case COM: bytesToSkip = getFieldSize(); if (bytesToSkip < markerSize) { throw ExifParsingError(); } m_stream.seekg( static_cast<long>( bytesToSkip - markerSize ), m_stream.cur ); if ( m_stream.fail() ) { throw ExifParsingError(); } break; //SOI and EOI don't have the size field after the marker case SOI: case EOI: break; case APP1: //actual Exif Marker exifSize = getFieldSize(); if (exifSize <= offsetToTiffHeader) { throw ExifParsingError(); } m_data.resize( exifSize - offsetToTiffHeader ); m_stream.seekg( static_cast<long>( offsetToTiffHeader ), m_stream.cur ); if ( m_stream.fail() ) { throw ExifParsingError(); } m_stream.read( reinterpret_cast<char*>(&m_data[0]), exifSize - offsetToTiffHeader ); count = m_stream.gcount(); exifFound = true; break; default: //No other markers are expected according to standard. May be a signal of error stopSearch = true; break; } } if( !exifFound ) { return m_exif; } parseExif(); return m_exif; }
/** * @brief Get exif directory structure contained in jpeg file (if any) * This is internal function and is not exposed to client * * @return Map where key is tag number and value is ExifEntry_t structure */ std::map<int, ExifEntry_t > ExifReader::getExif() { const size_t markerSize = 2; const size_t offsetToTiffHeader = 6; //bytes from Exif size field to the first TIFF header unsigned char appMarker[markerSize]; m_exif.erase( m_exif.begin(), m_exif.end() ); size_t count; FILE* f = fopen( m_filename.c_str(), "rb" ); if( !f ) { return m_exif; //Until this moment the map is empty } bool exifFound = false; while( ( !feof( f ) ) && !exifFound ) { count = fread( appMarker, sizeof(unsigned char), markerSize, f ); if( count < markerSize ) { break; } unsigned char marker = appMarker[1]; size_t bytesToSkip; size_t exifSize; switch( marker ) { //For all the markers just skip bytes in file pointed by followed two bytes (field size) case SOF0: case SOF2: case DHT: case DQT: case DRI: case SOS: case RST0: case RST1: case RST2: case RST3: case RST4: case RST5: case RST6: case RST7: case APP0: case APP2: case APP3: case APP4: case APP5: case APP6: case APP7: case APP8: case APP9: case APP10: case APP11: case APP12: case APP13: case APP14: case APP15: case COM: bytesToSkip = getFieldSize( f ); fseek( f, static_cast<long>( bytesToSkip - markerSize ), SEEK_CUR ); break; //SOI and EOI don't have the size field after the marker case SOI: case EOI: break; case APP1: //actual Exif Marker exifSize = getFieldSize(f); if (exifSize <= offsetToTiffHeader) { throw ExifParsingError(); } m_data.resize( exifSize - offsetToTiffHeader ); fseek(f, static_cast<long>( offsetToTiffHeader ), SEEK_CUR); count = fread( &m_data[0], sizeof( unsigned char ), exifSize - offsetToTiffHeader, f ); exifFound = true; break; default: //No other markers are expected according to standard. May be a signal of error break; } } fclose(f); if( !exifFound ) { return m_exif; } parseExif(); return m_exif; }