diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f7deff6..570e5742 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -87,8 +87,6 @@ if( EXIV2_ENABLE_BUILD_PO ) add_subdirectory( po ) endif() -add_subdirectory( bigtiff ) - ## # tests add_custom_target(tests COMMAND env EXIV2_BINDIR="${CMAKE_BINARY_DIR}"/bin make tests WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" ) diff --git a/bigtiff/CMakeLists.txt b/bigtiff/CMakeLists.txt deleted file mode 100644 index 44f5798f..00000000 --- a/bigtiff/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ - -add_executable(big_tiff_parser - parse.cpp -) - -target_include_directories(big_tiff_parser PRIVATE - ${CMAKE_SOURCE_DIR}/include/exiv2 - ${CMAKE_SOURCE_DIR}/src -) - -target_link_libraries(big_tiff_parser PRIVATE exiv2lib) diff --git a/bigtiff/parse.cpp b/bigtiff/parse.cpp deleted file mode 100644 index 31fa53b3..00000000 --- a/bigtiff/parse.cpp +++ /dev/null @@ -1,505 +0,0 @@ - -#include -#include -#include -#include -#include - -#include "basicio.hpp" -#include "iptc.hpp" -#include "image_int.hpp" -#include "image.hpp" -#include "types.hpp" - -#define WIDTH 32 - -// helpful links: -// http://www.awaresystems.be/imaging/tiff/bigtiff.html -// http://bigtiff.org/ -// http://bigtiff.org/libtiff-4.1.zip -// https://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c - -enum TypeId { - unsignedByte = 1, //!< Exif BYTE type, 8-bit unsigned integer. - asciiString = 2, //!< Exif ASCII type, 8-bit byte. - unsignedShort = 3, //!< Exif SHORT type, 16-bit (2-byte) unsigned integer. - unsignedLong = 4, //!< Exif LONG type, 32-bit (4-byte) unsigned integer. - unsignedRational = 5, //!< Exif RATIONAL type, two LONGs: numerator and denumerator of a fraction. - signedByte = 6, //!< Exif SBYTE type, an 8-bit signed (twos-complement) integer. - undefined = 7, //!< Exif UNDEFINED type, an 8-bit byte that may contain anything. - signedShort = 8, //!< Exif SSHORT type, a 16-bit (2-byte) signed (twos-complement) integer. - signedLong = 9, //!< Exif SLONG type, a 32-bit (4-byte) signed (twos-complement) integer. - signedRational = 10, //!< Exif SRATIONAL type, two SLONGs: numerator and denumerator of a fraction. - tiffFloat = 11, //!< TIFF FLOAT type, single precision (4-byte) IEEE format. - tiffDouble = 12, //!< TIFF DOUBLE type, double precision (8-byte) IEEE format. - tiffIfd = 13, //!< TIFF IFD type, 32-bit (4-byte) unsigned integer. - unsigned64 = 16, //!< 64-bit unsigned value - signed64 = 17, //!< 64-bit signed value - tiffIfd8 = 18, //!< 64-bit IFD offset - iptcString = 0x10000, //!< IPTC string type. - iptcDate = 0x10001, //!< IPTC date type. - iptcTime = 0x10002, //!< IPTC time type. - comment = 0x10003, //!< %Exiv2 type for the Exif user comment. - directory = 0x10004, //!< %Exiv2 type for a CIFF directory. - xmpText = 0x10005, //!< XMP text type. - xmpAlt = 0x10006, //!< XMP alternative type. - xmpBag = 0x10007, //!< XMP bag type. - xmpSeq = 0x10008, //!< XMP sequence type. - langAlt = 0x10009, //!< XMP language alternative type. - invalidTypeId = 0x1fffe, //!< Invalid type id. - lastTypeId = 0x1ffff //!< Last type id. -}; - -bool isStringType(uint16_t type) -{ - return type == asciiString - || type == unsignedByte - || type == signedByte - || type == undefined; -} - -bool isShortType(uint16_t type) -{ - return type == unsignedShort - || type == signedShort; -} - -bool isLongType(uint16_t type) -{ - return type == unsignedLong - || type == signedLong; -} - -bool isLongLongType(uint16_t type) -{ - return type == unsigned64 - || type == signed64; -} - -bool isRationalType(uint16_t type) -{ - return type == unsignedRational - || type == signedRational; -} - -bool is2ByteType(uint16_t type) -{ - return isShortType(type); -} - -bool is4ByteType(uint16_t type) -{ - return isLongType(type) - || type == tiffFloat - || type == tiffIfd; -} - -bool is8ByteType(uint16_t type) -{ - return isRationalType(type) - || type == tiffDouble - || type == unsigned64 - || type == signed64 - || type == tiffIfd8; -} - -bool isBigEndianPlatform() -{ - union - { - uint32_t i; - char c[4]; - } e = { 0x01000000 }; - - return e.c[0]?true:false; -} - -bool isLittleEndianPlatform() { return !isBigEndianPlatform(); } - -template -struct TypeForSize {}; - -template<> -struct TypeForSize<16> -{ - typedef int16_t Type; -}; - -template<> -struct TypeForSize<32> -{ - typedef int32_t Type; -}; - -template<> -struct TypeForSize<64> -{ - typedef int64_t Type; -}; - -template -typename TypeForSize::Type byte_swap(const typename TypeForSize::Type& v) -{ - typename TypeForSize::Type result = 0; - if (size == 16) - result = __builtin_bswap16(v); - else if (size == 32) - result = __builtin_bswap32(v); - else if (size == 64) - result = __builtin_bswap64(v); - - return result; -} - -template -typename TypeForSize::Type conditional_byte_swap(const typename TypeForSize::Type& v, bool swap) -{ - const typename TypeForSize::Type result = swap? byte_swap(v): v; - - return result; -} - - -template -typename TypeForSize::Type conditional_byte_swap_4_array(void* buf, uint64_t offset, bool swap) -{ - typedef typename TypeForSize::Type Type; - - const uint8_t* bytes_buf = static_cast(buf); - const Type* value = reinterpret_cast(&bytes_buf[offset]); - - return conditional_byte_swap(*value, swap); -} - - -std::string indent(int32_t d) -{ - std::string result ; - if ( d > 0 ) - while ( d--) - result += " "; - - return result; -} - -static const char* tagName(uint16_t tag,size_t nMaxLength) -{ - const char* result = NULL; -/* - // build a static map of tags for fast search - static std::map tags; - static bool init = true; - static char buffer[80]; - - if ( init ) { - int idx; - const TagInfo* ti ; - for (ti = mnTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = iopTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = gpsTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = ifdTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = mpfTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - for (ti = Nikon1MakerNote::tagList(), idx = 0 - ; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_; - } - init = false; - - try { - result = tags[tag].c_str(); - if ( nMaxLength > sizeof(buffer) -2 ) - nMaxLength = sizeof(buffer) -2; - strncpy(buffer,result,nMaxLength); - result = buffer; - } catch ( ... ) {} -*/ - return result ; -} - -static const char* typeName(uint16_t tag) -{ - //! List of TIFF image tags - const char* result = NULL; - switch (tag ) { - case unsignedByte : result = "BYTE" ; break; - case asciiString : result = "ASCII" ; break; - case unsignedShort : result = "SHORT" ; break; - case unsignedLong : result = "LONG" ; break; - case unsignedRational : result = "RATIONAL" ; break; - case signedByte : result = "SBYTE" ; break; - case undefined : result = "UNDEFINED" ; break; - case signedShort : result = "SSHORT" ; break; - case signedLong : result = "SLONG" ; break; - case signedRational : result = "SRATIONAL" ; break; - case tiffFloat : result = "FLOAT" ; break; - case tiffDouble : result = "DOUBLE" ; break; - case tiffIfd : result = "IFD" ; break; - case unsigned64 : result = "UNSIGNED64"; break; - case signed64 : result = "SIGNED64" ; break; - default : result = "unknown" ; break; - } - return result; -} - -struct field_t { - uint16_t tagID; - uint16_t tagType; - uint64_t count; - uint64_t data; -} __attribute__((packed)); - -void printIFD(Exiv2::BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option, uint64_t offset, bool bSwap, int depth) -{ - depth++; - bool bFirst = true; - - // buffer - bool bPrint = true; - - do - { - // Read top of directory - io.seek(offset, Exiv2::BasicIo::beg); - - uint64_t entries_raw; - io.read(reinterpret_cast(&entries_raw), 8); - - const uint64_t entries = conditional_byte_swap_4_array<64>(&entries_raw, 0, bSwap); - - const bool tooBig = entries > 500; - - if ( bFirst && bPrint ) - { - out << indent(depth) << Exiv2::Internal::stringFormat("STRUCTURE OF TIFF FILE ") << io.path() << std::endl; - if (tooBig) - out << indent(depth) << "entries = " << entries << std::endl; - } - - if (tooBig) - break; - - // Read the dictionary - for ( uint64_t i = 0; i < entries; i ++ ) - { - if ( bFirst && bPrint ) - out << indent(depth) - << " address | tag | " - << " type | count | offset | value\n"; - - bFirst = false; - field_t field; - - io.read(reinterpret_cast(&field), sizeof(field_t)); - const uint16_t tag = conditional_byte_swap<16>(field.tagID, bSwap); - const uint16_t type = conditional_byte_swap<16>(field.tagType, bSwap); - const uint64_t count = conditional_byte_swap<64>(field.count, bSwap); - const uint64_t data = conditional_byte_swap<64>(field.data, bSwap); - - std::string sp = "" ; // output spacer - - //prepare to print the value - // TODO: figure out what's going on with kount - const uint64_t kount = isStringType(type)? (count > 32 ? 32 : count) // restrict long arrays - : count > 5 ? 5 - : count - ; - const uint32_t pad = isStringType(type) ? 1 : 0; - const uint32_t size = isStringType(type) ? 1 - : is2ByteType(type) ? 2 - : is4ByteType(type) ? 4 - : is8ByteType(type) ? 8 - : 1; - - Exiv2::DataBuf buf(size * count + pad); - - // big data? Use 'data' as pointer to real data - if ( count*size > 8 ) // read into buffer - { - size_t restore = io.tell(); // save - io.seek(data, Exiv2::BasicIo::beg); // position - io.read(buf.pData_, count * size); // read - io.seek(restore, Exiv2::BasicIo::beg); // restore - } - else // use 'data' as data :) - std::memcpy(buf.pData_, &data, count * size); // copy data - - if ( bPrint ) - { - const uint64_t address = offset + 2 + i * sizeof(field_t) ; - out << indent(depth) - << Exiv2::Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%10u | ", - address, tag, tagName(tag,25), typeName(type), count, offset); - - if ( isShortType(type) ) - { - for ( size_t k = 0 ; k < kount ; k++ ) - { - out << sp << conditional_byte_swap_4_array<16>(buf.pData_, k*size, bSwap); - sp = " "; - } - } - else if ( isLongType(type) ) - { - for ( size_t k = 0 ; k < kount ; k++ ) - { - out << sp << conditional_byte_swap_4_array<32>(buf.pData_, k*size, bSwap); - sp = " "; - } - } - else if ( isLongLongType(type) ) - { - for ( size_t k = 0 ; k < kount ; k++ ) - { - out << sp << conditional_byte_swap_4_array<64>(buf.pData_, k*size, bSwap); - sp = " "; - } - } - else if ( isRationalType(type) ) - { - for ( size_t k = 0 ; k < kount ; k++ ) - { - uint32_t a = conditional_byte_swap_4_array<32>(buf.pData_, k*size+0, bSwap); - uint32_t b = conditional_byte_swap_4_array<32>(buf.pData_, k*size+4, bSwap); - out << sp << a << "/" << b; - sp = " "; - } - } - else if ( isStringType(type) ) - out << sp << Exiv2::Internal::binaryToString(buf, kount); - - sp = kount == count ? "" : " ..."; - out << sp << std::endl; - - if ( option == Exiv2::kpsRecursive && - (tag == 0x8769 /* ExifTag */ || tag == 0x014a/*SubIFDs*/ || type == tiffIfd || type == tiffIfd8) ) - { - for ( size_t k = 0 ; k < count ; k++ ) - { - const size_t restore = io.tell(); - const uint64_t offset = type == tiffIfd8? - conditional_byte_swap_4_array<64>(buf.pData_, k*size, bSwap): - conditional_byte_swap_4_array<32>(buf.pData_, k*size, bSwap); - - std::cerr << "tag = " << Exiv2::Internal::stringFormat("%#x",tag) << std::endl; - printIFD(io, out, option, offset, bSwap, depth); - io.seek(restore, Exiv2::BasicIo::beg); - } - } - else if ( option == Exiv2::kpsRecursive && tag == 0x83bb /* IPTCNAA */ ) - { - size_t restore = io.tell(); // save - io.seek(offset, Exiv2::BasicIo::beg); // position - Exiv2::byte* bytes=new Exiv2::byte[count] ; // allocate memory - io.read(bytes,count) ; // read - io.seek(restore, Exiv2::BasicIo::beg); // restore - Exiv2::IptcData::printStructure(out,bytes,count,depth); - delete[] bytes; // free - } - else if ( option == Exiv2::kpsRecursive && tag == 0x927c /* MakerNote */ && count > 10) - { - size_t restore = io.tell(); // save - - uint32_t jump= 10 ; - Exiv2::byte bytes[20] ; - const char* chars = (const char*) &bytes[0] ; - io.seek(offset, Exiv2::BasicIo::beg); // position - io.read(bytes,jump ) ; // read - bytes[jump]=0 ; - if ( ::strcmp("Nikon",chars) == 0 ) - { - // tag is an embedded tiff - Exiv2::byte* bytes=new Exiv2::byte[count-jump] ; // allocate memory - io.read(bytes,count-jump) ; // read - Exiv2::MemIo memIo(bytes,count-jump) ; // create a file - std::cerr << "Nikon makernote" << std::endl; - // printTiffStructure(memIo,out,option,depth); TODO: fix it - delete[] bytes ; // free - } - else - { - // tag is an IFD - io.seek(0, Exiv2::BasicIo::beg); // position - std::cerr << "makernote" << std::endl; - //printIFDStructure(io,out,option,offset,bSwap,c,depth); // TODO: fix me - } - - io.seek(restore,Exiv2::BasicIo::beg); // restore - } - } - } - uint64_t next_dir_offset_raw; - io.read(reinterpret_cast(&next_dir_offset_raw), 8); - offset = tooBig ? 0 : conditional_byte_swap_4_array<64>(&next_dir_offset_raw, 0, bSwap); - out.flush(); - } while (offset) ; - - if ( bPrint ) - out << indent(depth) << "END " << io.path() << std::endl; - - depth--; -} - -int main(int argc,const char* argv[]) -{ - int result = 0; - bool bSwap = false; - uint64_t offset = 0; - - if ( argc > 0 ) - { - FILE* f = fopen(argv[1],"rb"); - if ( f ) - { - char buff[2*WIDTH]; - fread(buff, 1, sizeof buff, f); - - bSwap = (isLittleEndianPlatform() && buff[0] == 'M') - || (isBigEndianPlatform() && buff[0] == 'I') - ; - - uint16_t magic = conditional_byte_swap_4_array<16>(buff, 2, bSwap); - uint16_t byteSize = conditional_byte_swap_4_array<16>(buff, 4, bSwap); - uint16_t zeroByte = conditional_byte_swap_4_array<16>(buff, 6, bSwap); - offset = conditional_byte_swap_4_array<64>(buff, 8, bSwap); - - if ( buff[0] != buff[1] || - (buff[0] != 'I' && buff[0] != 'M') || - magic != 43 || - byteSize != 8 || - zeroByte != 0 - ) - { - std::cerr << "bSwap = " << bSwap << std::endl; - std::cerr << "magic = " << magic << std::endl; - std::cerr << "byteSize = " << byteSize << std::endl; - std::cerr << "zeroByte = " << zeroByte << std::endl; - std::cerr << "offset = " << offset << std::endl; - std::cerr << argv[1] << " is not a BigTIFF file" << std::endl; - result = 3 ; - } - - fclose(f); - } - else - { - std::cerr << argv[0] << " unable to open " << argv[1] << std::endl; - result = 2 ; - } - - } - else - { - std::cerr << argv[0] << " path" << std::endl; - result = 1 ; - } - - if ( result == 0 ) { - std::cout << "Congrats swap = " << (bSwap?"true":"false") << " offset = " << offset << std::endl; - int depth = 0 ; - Exiv2::FileIo file(argv[1]); - file.open("rb"); - printIFD(file, std::cout, Exiv2::kpsRecursive, offset, bSwap, depth); - } - - return result; -}