Merges all changes from the insideout branch back into trunk. This includes the IO abstraction code, split-up of image.cpp, and inside-out design change (#402, #403, and #404).
parent
cbfe3eead2
commit
0cab366ec2
@ -1,351 +1,363 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="exiv2lib"
|
||||
ProjectGUID="{831EF580-92C8-4CA8-B0CE-3D906280A54D}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\src;..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
BufferSecurityCheck="TRUE"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/exiv2.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\src;..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="4"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/exiv2.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\..\src\canonmn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\datasets.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\exif.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\fujimn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ifd.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\image.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\iptc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\makernote.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\metadatum.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\mn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\nikonmn.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\sigmamn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tags.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\types.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\value.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath="..\..\src\canonmn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\config.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\datasets.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\error.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\exif.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\fujimn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ifd.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\image.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\iptc.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\makernote.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\metadatum.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\nikonmn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\rcsid.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\sigmamn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tags.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\types.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\value.hpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="exiv2lib"
|
||||
ProjectGUID="{831EF580-92C8-4CA8-B0CE-3D906280A54D}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="..\..\src;..\.."
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
BufferSecurityCheck="TRUE"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/exiv2.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="..\..\src;..\.."
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
|
||||
RuntimeLibrary="4"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
BrowseInformation="1"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLibrarianTool"
|
||||
OutputFile="$(OutDir)/exiv2.lib"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\..\src\basicio.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\canonmn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\datasets.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\exif.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\fujimn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ifd.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\image.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\iptc.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\jpgimage.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\makernote.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\metadatum.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\mn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\nikonmn.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\sigmamn.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tags.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\types.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\value.cpp">
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
ObjectFile="$(IntDir)/$(InputName)1.obj"/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
<File
|
||||
RelativePath="..\..\src\basicio.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\canonmn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\config.h">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\datasets.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\error.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\exif.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\fujimn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\ifd.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\image.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\iptc.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\jpgimage.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\makernote.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\metadatum.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\nikonmn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\rcsid.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\sigmamn.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\tags.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\types.hpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\value.hpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
|
@ -0,0 +1,141 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="iotest"
|
||||
ProjectGUID="{5D43ECB3-681D-4732-9395-AB81CD283F6C}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""..\..\src";"..\..""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
BufferSecurityCheck="TRUE"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\exiv2lib\Debug\exiv2.lib"
|
||||
OutputFile="$(OutDir)/iotest.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/iotest.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""..\..\src";"..\..""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="4"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\exiv2lib\Release\exiv2.lib"
|
||||
OutputFile="$(OutDir)/iotest.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\..\src\iotest.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -0,0 +1,144 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="7.10"
|
||||
Name="iptceasy"
|
||||
ProjectGUID="{D8B36F3A-34BB-4540-A731-EEABF1DC2E05}"
|
||||
Keyword="Win32Proj">
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"/>
|
||||
</Platforms>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="Debug"
|
||||
IntermediateDirectory="Debug"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories=""..\..\src";"..\..""
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
|
||||
MinimalRebuild="TRUE"
|
||||
BasicRuntimeChecks="3"
|
||||
RuntimeLibrary="5"
|
||||
BufferSecurityCheck="TRUE"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="4"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\exiv2lib\Debug\exiv2.lib"
|
||||
OutputFile="$(OutDir)/iptceasy.exe"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="TRUE"
|
||||
ProgramDatabaseFile="$(OutDir)/iptceasy.pdb"
|
||||
SubSystem="1"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="Release"
|
||||
IntermediateDirectory="Release"
|
||||
ConfigurationType="1"
|
||||
CharacterSet="2">
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories=""..\..\src";"..\..""
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
|
||||
RuntimeLibrary="4"
|
||||
RuntimeTypeInfo="TRUE"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
WarnAsError="TRUE"
|
||||
Detect64BitPortabilityProblems="TRUE"
|
||||
DebugInformationFormat="3"/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\exiv2lib\Release\exiv2.lib"
|
||||
OutputFile="$(OutDir)/iptceasy.exe"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="TRUE"
|
||||
SubSystem="1"
|
||||
OptimizeReferences="2"
|
||||
EnableCOMDATFolding="2"
|
||||
TargetMachine="1"/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"/>
|
||||
<Tool
|
||||
Name="VCManagedWrapperGeneratorTool"/>
|
||||
<Tool
|
||||
Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
|
||||
<File
|
||||
RelativePath="..\..\src\iptceasy.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\..\src\mn.cpp">
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
@ -0,0 +1,427 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
/*
|
||||
File: basicio.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Brad Schick (brad) <brad@robotbattle.com>
|
||||
History: 04-Dec-04, brad: created
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$");
|
||||
|
||||
// Define DEBUG_MAKERNOTE to output debug information to std::cerr
|
||||
#undef DEBUG_MAKERNOTE
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "basicio.hpp"
|
||||
#include "types.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <cassert>
|
||||
#include <sys/types.h> // for stat()
|
||||
#include <sys/stat.h> // for stat()
|
||||
#ifdef HAVE_PROCESS_H
|
||||
# include <process.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h> // for getpid, stat
|
||||
#endif
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
|
||||
FileIo::FileIo(const std::string& path) :
|
||||
path_(path), fp_(0), opMode_(opSeek)
|
||||
{
|
||||
}
|
||||
|
||||
FileIo::~FileIo()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
BasicIo::AutoPtr FileIo::temporary() const
|
||||
{
|
||||
BasicIo::AutoPtr basicIo;
|
||||
|
||||
struct stat buf;
|
||||
int ret = stat(path_.c_str(), &buf);
|
||||
|
||||
// If file is > 1MB then use a file, otherwise use memory buffer
|
||||
if (buf.st_size > 1048576 || ret != 0) {
|
||||
pid_t pid = getpid();
|
||||
std::string tmpname = path_ + toString(pid);
|
||||
FileIo *fileIo = new FileIo(tmpname);
|
||||
if (fileIo->open("w+b") != 0 ) {
|
||||
delete fileIo;
|
||||
}
|
||||
else {
|
||||
basicIo.reset(fileIo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
basicIo.reset(new MemIo);
|
||||
}
|
||||
|
||||
return basicIo;
|
||||
}
|
||||
|
||||
long FileIo::write(const byte* data, long wcount )
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
|
||||
// ANSI C requires a flush or seek when switching
|
||||
// between read and write modes.
|
||||
if (opMode_ == opRead) {
|
||||
// on msvcrt fflush does not do the job
|
||||
fseek(fp_, 0, SEEK_CUR);
|
||||
}
|
||||
opMode_ = opWrite;
|
||||
return (long)fwrite(data, 1, wcount, fp_);
|
||||
}
|
||||
|
||||
long FileIo::write(BasicIo& src)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
if (static_cast<BasicIo*>(this)==&src) return 0;
|
||||
if (!src.isopen()) return 0;
|
||||
|
||||
// ANSI C requires a flush or seek when switching
|
||||
// between read and write modes.
|
||||
if (opMode_ == opRead) {
|
||||
// on msvcrt fflush does not do the job
|
||||
fseek(fp_, 0, SEEK_CUR);
|
||||
}
|
||||
opMode_ = opWrite;
|
||||
|
||||
byte buf[4096];
|
||||
long readCount = 0;
|
||||
long writeCount = 0;
|
||||
long writeTotal = 0;
|
||||
while ((readCount = src.read(buf, sizeof(buf)))) {
|
||||
writeTotal += writeCount = (long)fwrite(buf, 1, readCount, fp_);
|
||||
if (writeCount != readCount) {
|
||||
// try to reset back to where write stopped
|
||||
src.seek(writeCount-readCount, BasicIo::cur);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return writeTotal;
|
||||
}
|
||||
|
||||
int FileIo::transfer(BasicIo& src)
|
||||
{
|
||||
const bool wasOpen = (fp_ != 0);
|
||||
const std::string lastMode(openMode_);
|
||||
|
||||
FileIo *fileIo = dynamic_cast<FileIo*>(&src);
|
||||
if (fileIo) {
|
||||
// Optimization if this is another instance of FileIo
|
||||
close();
|
||||
fileIo->close();
|
||||
// MSVCRT rename that does not overwrite existing files
|
||||
if (remove(path_.c_str()) != 0) return -4;
|
||||
if (rename(fileIo->path_.c_str(), path_.c_str()) == -1) return -4;
|
||||
remove(fileIo->path_.c_str());
|
||||
}
|
||||
else{
|
||||
// Generic handling, reopen both to reset to start
|
||||
open("w+b");
|
||||
if (src.open() !=0) return 1;
|
||||
write(src);
|
||||
src.close();
|
||||
}
|
||||
|
||||
if (wasOpen) open(lastMode);
|
||||
else close();
|
||||
|
||||
return error() || src.error();
|
||||
}
|
||||
|
||||
int FileIo::putb(byte data)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
if (opMode_ == opRead) {
|
||||
// on msvcrt fflush does not do the job
|
||||
fseek(fp_, 0, SEEK_CUR);
|
||||
}
|
||||
opMode_ = opWrite;
|
||||
return putc(data, fp_);
|
||||
}
|
||||
|
||||
int FileIo::seek(long offset, Position pos)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
int fileSeek;
|
||||
if (pos == BasicIo::cur) {
|
||||
fileSeek = SEEK_CUR;
|
||||
}
|
||||
else if (pos == BasicIo::beg) {
|
||||
fileSeek = SEEK_SET;
|
||||
}
|
||||
else {
|
||||
assert(pos == BasicIo::end);
|
||||
fileSeek = SEEK_END;
|
||||
}
|
||||
|
||||
opMode_ = opSeek;
|
||||
return fseek(fp_, offset, fileSeek);
|
||||
}
|
||||
|
||||
long FileIo::tell() const
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
return ftell(fp_);
|
||||
}
|
||||
|
||||
int FileIo::open()
|
||||
{
|
||||
// Default open is in read-write binary mode
|
||||
return open("r+b");
|
||||
}
|
||||
|
||||
int FileIo::open(const std::string& mode)
|
||||
{
|
||||
if (fp_ != 0) {
|
||||
fclose(fp_);
|
||||
}
|
||||
|
||||
openMode_ = mode;
|
||||
opMode_ = opSeek;
|
||||
fp_ = fopen(path_.c_str(), mode.c_str());
|
||||
if (!fp_) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool FileIo::isopen() const
|
||||
{
|
||||
return fp_ != 0;
|
||||
}
|
||||
|
||||
int FileIo::close()
|
||||
{
|
||||
if (fp_ != 0) {
|
||||
fclose(fp_);
|
||||
fp_= 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DataBuf FileIo::read(long rcount)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
DataBuf buf(rcount);
|
||||
long readCount = read(buf.pData_, buf.size_);
|
||||
buf.size_ = readCount;
|
||||
return buf;
|
||||
}
|
||||
|
||||
long FileIo::read(byte* buf, long rcount)
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
|
||||
if (opMode_ == opWrite) {
|
||||
// on msvcrt fflush does not do the job
|
||||
fseek(fp_, 0, SEEK_CUR);
|
||||
}
|
||||
opMode_ = opRead;
|
||||
return (long)fread(buf, 1, rcount, fp_);
|
||||
}
|
||||
|
||||
int FileIo::getb()
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
|
||||
if (opMode_ == opWrite) {
|
||||
// on msvcrt fflush does not do the job
|
||||
fseek(fp_, 0, SEEK_CUR);
|
||||
}
|
||||
opMode_ = opRead;
|
||||
return getc(fp_);
|
||||
}
|
||||
|
||||
int FileIo::error() const
|
||||
{
|
||||
return fp_ != 0 ? ferror(fp_) : 0;
|
||||
}
|
||||
|
||||
bool FileIo::eof() const
|
||||
{
|
||||
assert(fp_ != 0);
|
||||
return feof(fp_) != 0;
|
||||
}
|
||||
|
||||
|
||||
MemIo::MemIo(const byte* data, long size)
|
||||
{
|
||||
// If copying data is too slow it might be worth
|
||||
// creating a readonly MemIo variant
|
||||
data_.reserve(size);
|
||||
data_.assign(data, data+size);
|
||||
idx_ = 0;
|
||||
}
|
||||
|
||||
BasicIo::AutoPtr MemIo::temporary() const
|
||||
{
|
||||
return BasicIo::AutoPtr(new MemIo);
|
||||
}
|
||||
|
||||
void MemIo::checkSize(long wcount)
|
||||
{
|
||||
ByteVector::size_type need = wcount + idx_;
|
||||
if (need > data_.size()) {
|
||||
data_.resize(need);
|
||||
}
|
||||
}
|
||||
|
||||
long MemIo::write(const byte* data, long wcount )
|
||||
{
|
||||
checkSize(wcount);
|
||||
// According to Josuttis 6.2.3 this is safe
|
||||
memcpy(&data_[idx_], data, wcount);
|
||||
idx_ += wcount;
|
||||
return wcount;
|
||||
}
|
||||
|
||||
int MemIo::transfer(BasicIo& src)
|
||||
{
|
||||
MemIo *memIo = dynamic_cast<MemIo*>(&src);
|
||||
if (memIo) {
|
||||
// Optimization if this is another instance of MemIo
|
||||
data_.swap(memIo->data_);
|
||||
idx_ = 0;
|
||||
}
|
||||
else{
|
||||
// Generic reopen to reset position to start
|
||||
data_.clear();
|
||||
idx_ = 0;
|
||||
if (src.open() != 0) return 1;
|
||||
write(src);
|
||||
src.close();
|
||||
}
|
||||
return error() || src.error();
|
||||
}
|
||||
|
||||
long MemIo::write(BasicIo& src)
|
||||
{
|
||||
if (static_cast<BasicIo*>(this)==&src) return 0;
|
||||
if (!src.isopen()) return 0;
|
||||
|
||||
byte buf[4096];
|
||||
long readCount = 0;
|
||||
long writeTotal = 0;
|
||||
while ((readCount = src.read(buf, sizeof(buf)))) {
|
||||
write(buf, readCount);
|
||||
writeTotal += readCount;
|
||||
}
|
||||
|
||||
return writeTotal;
|
||||
}
|
||||
|
||||
int MemIo::putb(byte data)
|
||||
{
|
||||
checkSize(1);
|
||||
data_[idx_++] = data;
|
||||
return data;
|
||||
}
|
||||
|
||||
int MemIo::seek(long offset, Position pos)
|
||||
{
|
||||
ByteVector::size_type newIdx;
|
||||
|
||||
if (pos == BasicIo::cur ) {
|
||||
newIdx = idx_ + offset;
|
||||
}
|
||||
else if (pos == BasicIo::beg) {
|
||||
newIdx = offset;
|
||||
}
|
||||
else {
|
||||
assert(pos == BasicIo::end);
|
||||
newIdx = data_.size() + offset;
|
||||
}
|
||||
|
||||
if (newIdx < 0 || newIdx > data_.size()) return 1;
|
||||
idx_ = newIdx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long MemIo::tell() const
|
||||
{
|
||||
return (long)idx_;
|
||||
}
|
||||
|
||||
int MemIo::open()
|
||||
{
|
||||
idx_ = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MemIo::isopen() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int MemIo::close()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DataBuf MemIo::read(long rcount)
|
||||
{
|
||||
DataBuf buf(rcount);
|
||||
long readCount = read(buf.pData_, buf.size_);
|
||||
buf.size_ = readCount;
|
||||
return buf;
|
||||
}
|
||||
|
||||
long MemIo::read(byte* buf, long rcount)
|
||||
{
|
||||
long avail = (long)(data_.size() - idx_);
|
||||
long allow = std::min(rcount, avail);
|
||||
|
||||
// According to Josuttis 6.2.3 this is safe
|
||||
memcpy(buf, &data_[idx_], allow);
|
||||
idx_ += allow;
|
||||
return allow;
|
||||
}
|
||||
|
||||
int MemIo::getb()
|
||||
{
|
||||
if (idx_ == data_.size())
|
||||
return EOF;
|
||||
return data_[idx_++];
|
||||
}
|
||||
|
||||
int MemIo::error() const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool MemIo::eof() const
|
||||
{
|
||||
return idx_ == data_.size();
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
@ -0,0 +1,605 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
/*!
|
||||
@file basicio.hpp
|
||||
@brief Simple binary IO abstraction
|
||||
@version $Rev$
|
||||
@author Brad Schick (brad)
|
||||
<a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
|
||||
@date 04-Dec-04, brad: created
|
||||
*/
|
||||
#ifndef BASICIO_HPP_
|
||||
#define BASICIO_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
/*!
|
||||
@brief An interface for simple binary IO.
|
||||
|
||||
Designed to have semantics
|
||||
and names similar to those of C style FILE* operations. Subclasses
|
||||
should all behave the same so that they can be interchanged.
|
||||
*/
|
||||
class BasicIo
|
||||
{
|
||||
public:
|
||||
//! BasicIo auto_ptr type
|
||||
typedef std::auto_ptr<BasicIo> AutoPtr;
|
||||
|
||||
//! Seek starting positions
|
||||
enum Position { beg, cur, end };
|
||||
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Destructor
|
||||
virtual ~BasicIo() {}
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Open the IO source using the default access mode. The
|
||||
default mode should allow for reading and writing.
|
||||
|
||||
This method can also be used to "reopen" an IO source which will
|
||||
flush any unwritten data and reset the IO position to the start.
|
||||
Subclasses may provide custom methods to allow for
|
||||
opening IO sources differently.
|
||||
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int open() = 0;
|
||||
/*!
|
||||
@brief Close the IO source. After closing a BasicIo instance can not
|
||||
be read or written. Closing flushes any unwritten data. It is
|
||||
safe to call close on a closed instance.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int close() = 0;
|
||||
/*!
|
||||
@brief Write data to the IO source. Current IO position is advanced
|
||||
by the number of bytes written.
|
||||
@param data Pointer to data. Data must be at least \em wcount
|
||||
bytes long
|
||||
@param wcount Number of bytes to be written.
|
||||
@return Number of bytes written to IO source successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(const byte* data, long wcount) = 0;
|
||||
/*!
|
||||
@brief Write data that is read from another BasicIo instance to
|
||||
the IO source. Current IO position is advanced by the number
|
||||
of bytes written.
|
||||
@param src Reference to another BasicIo instance. Reading start
|
||||
at the source's current IO position
|
||||
@return Number of bytes written to IO source successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(BasicIo& src) = 0;
|
||||
/*!
|
||||
@brief Write one byte to the IO source. Current IO position is
|
||||
advanced by one byte.
|
||||
@param data The single byte to be written.
|
||||
@return The value of the byte written if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int putb(byte data) = 0;
|
||||
/*!
|
||||
@brief Read data from the IO source. Reading starts at the current
|
||||
IO position and the position is advanced by the number of bytes
|
||||
read.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return DataBuf instance containing the bytes read. Use the
|
||||
DataBuf::size_ member to find the number of bytes read.
|
||||
DataBuf::size_ will be 0 on failure.
|
||||
*/
|
||||
virtual DataBuf read(long rcount) = 0;
|
||||
/*!
|
||||
@brief Read data from the IO source. Reading starts at the current
|
||||
IO position and the position is advanced by the number of bytes
|
||||
read.
|
||||
@param buf Pointer to a block of memory into which the read data
|
||||
is stored. The memory block must be at least \em rcount bytes
|
||||
long.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return Number of bytes read from IO source successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long read(byte *buf, long rcount) = 0;
|
||||
/*!
|
||||
@brief Read one byte from the IO source. Current IO position is
|
||||
advanced by one byte.
|
||||
@return The byte read from the IO source if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int getb() = 0;
|
||||
/*!
|
||||
@brief Remove all data from this object's IO source and then transfer
|
||||
data from the \em src BasicIo object into this object.
|
||||
|
||||
The source object is invalidated by this operation and should not be
|
||||
used after this method returns. This method exists primarily to
|
||||
be used with the BasicIo::temporary() method.
|
||||
|
||||
@param src Reference to another BasicIo instance. The entire contents
|
||||
of src are transferred to this object. The \em src object is
|
||||
invalidated by the method.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int transfer(BasicIo& src) = 0;
|
||||
/*!
|
||||
@brief Move the current IO position.
|
||||
@param offset Number of bytes to move the position relative
|
||||
to the starting position specified by \em pos
|
||||
@param pos Position from which the seek should start
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int seek(long offset, Position pos) = 0;
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Get the current IO position.
|
||||
@return Offset from the start of IO if successful;<BR>
|
||||
-l if failure;
|
||||
*/
|
||||
virtual long tell() const = 0;
|
||||
//!Returns true if the IO source is open, otherwise false.
|
||||
virtual bool isopen() const = 0;
|
||||
//!Returns 0 if the IO source is in a valid state, otherwise nonzero.
|
||||
virtual int error() const = 0;
|
||||
//!Returns true if the IO position has reach the end, otherwise false.
|
||||
virtual bool eof() const = 0;
|
||||
/*!
|
||||
@brief Returns a temporary data storage location. This is often
|
||||
needed to rewrite an IO source.
|
||||
|
||||
For example, data may be read from the original IO source, modified
|
||||
in some way, and then saved to the temporary instance. After the
|
||||
operation is complete, the BasicIo::transfer method can be used to
|
||||
replace the original IO source with the modified version. Subclasses
|
||||
are free to return any class that derives from BasicIo.
|
||||
|
||||
@return An instance of BasicIo on success;<BR>
|
||||
Null pointer on failure;
|
||||
*/
|
||||
virtual BasicIo::AutoPtr temporary() const = 0;
|
||||
//@}
|
||||
|
||||
protected:
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Default Constructor
|
||||
BasicIo() {}
|
||||
//@}
|
||||
}; // class BasicIo
|
||||
|
||||
/*!
|
||||
@brief Utility class that closes a BasicIo instance upon destruction.
|
||||
Meant to be used as a stack variable in functions that need to
|
||||
ensure BasicIo instances get closed. Useful when functions return
|
||||
errors from many locations.
|
||||
*/
|
||||
class IoCloser {
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Constructor, takes a BasicIo reference
|
||||
IoCloser(BasicIo &bio) : bio_(bio) {}
|
||||
//! Destructor, closes the BasicIo reference
|
||||
~IoCloser() { close(); }
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
//! Close the BasicIo if it is open
|
||||
void close() { if (bio_.isopen()) bio_.close(); }
|
||||
//@}
|
||||
|
||||
// DATA
|
||||
//! The BasicIo reference
|
||||
BasicIo &bio_;
|
||||
private:
|
||||
// Not implemented
|
||||
//! Copy constructor
|
||||
IoCloser(const IoCloser&);
|
||||
//! Assignment operator
|
||||
IoCloser& operator=(const IoCloser&);
|
||||
}; // class IoCloser
|
||||
|
||||
|
||||
/*!
|
||||
@brief Provides binary file IO by implementing the BasicIo
|
||||
interface.
|
||||
*/
|
||||
class FileIo : public BasicIo
|
||||
{
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor that accepts the file path on which IO will be
|
||||
performed. The constructor does not open the file, and
|
||||
therefore never failes.
|
||||
@param path The full path of a file
|
||||
*/
|
||||
FileIo(const std::string& path);
|
||||
//! Destructor. Flushes and closes an open file.
|
||||
virtual ~FileIo();
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Open the file using using the specified mode.
|
||||
|
||||
This method can also be used to "reopen" a file which will flush any
|
||||
unwritten data and reset the IO position to the start. Although
|
||||
files can be opened in binary or text mode, this class has
|
||||
only been tested carefully in binary mode.
|
||||
|
||||
@param mode Specified that type of access allowed on the file.
|
||||
Valid values match those of the C fopen command exactly.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
int open( const std::string& mode);
|
||||
/*!
|
||||
@brief Open the file using using the default access mode of "r+b".
|
||||
This method can also be used to "reopen" a file which will flush
|
||||
any unwritten data and reset the IO position to the start.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int open();
|
||||
/*!
|
||||
@brief Flush and unwritten data and close the file . It is
|
||||
safe to call close on an already closed instance.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int close();
|
||||
/*!
|
||||
@brief Write data to the file. The file position is advanced
|
||||
by the number of bytes written.
|
||||
@param data Pointer to data. Data must be at least \em wcount
|
||||
bytes long
|
||||
@param wcount Number of bytes to be written.
|
||||
@return Number of bytes written to the file successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(const byte* data, long wcount);
|
||||
/*!
|
||||
@brief Write data that is read from another BasicIo instance to
|
||||
the file. The file position is advanced by the number
|
||||
of bytes written.
|
||||
@param src Reference to another BasicIo instance. Reading start
|
||||
at the source's current IO position
|
||||
@return Number of bytes written to the file successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(BasicIo& src);
|
||||
/*!
|
||||
@brief Write one byte to the file. The file position is
|
||||
advanced by one byte.
|
||||
@param data The single byte to be written.
|
||||
@return The value of the byte written if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int putb(byte data);
|
||||
/*!
|
||||
@brief Read data from the file. Reading starts at the current
|
||||
file position and the position is advanced by the number of
|
||||
bytes read.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return DataBuf instance containing the bytes read. Use the
|
||||
DataBuf::size_ member to find the number of bytes read.
|
||||
DataBuf::size_ will be 0 on failure.
|
||||
*/
|
||||
virtual DataBuf read(long rcount);
|
||||
/*!
|
||||
@brief Read data from the file. Reading starts at the current
|
||||
file position and the position is advanced by the number of
|
||||
bytes read.
|
||||
@param buf Pointer to a block of memory into which the read data
|
||||
is stored. The memory block must be at least \em rcount bytes
|
||||
long.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return Number of bytes read from the file successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long read(byte *buf, long rcount);
|
||||
/*!
|
||||
@brief Read one byte from the file. The file position is
|
||||
advanced by one byte.
|
||||
@return The byte read from the file if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int getb();
|
||||
/*!
|
||||
@brief Remove the contents of the file and then transfer data from
|
||||
the \em src BasicIo object into the empty file.
|
||||
|
||||
This method is optimized to simply rename the source file if the
|
||||
source object is another FileIo instance. The source BasicIo object
|
||||
is invalidated by this operation and should not be used after this
|
||||
method returns. This method exists primarily to be used with
|
||||
the BasicIo::temporary() method.
|
||||
|
||||
@param src Reference to another BasicIo instance. The entire contents
|
||||
of src are transferred to this object. The \em src object is
|
||||
invalidated by the method.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int transfer(BasicIo& src);
|
||||
/*!
|
||||
@brief Move the current file position.
|
||||
@param offset Number of bytes to move the file position
|
||||
relative to the starting position specified by \em pos
|
||||
@param pos Position from which the seek should start
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int seek(long offset, Position pos);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Get the current file position.
|
||||
@return Offset from the start of the file if successful;<BR>
|
||||
-l if failure;
|
||||
*/
|
||||
virtual long tell() const;
|
||||
//!Returns true if the file is open, otherwise false.
|
||||
virtual bool isopen() const;
|
||||
//!Returns 0 if the file is in a valid state, otherwise nonzero.
|
||||
virtual int error() const;
|
||||
//!Returns true if the file position has reach the end, otherwise false.
|
||||
virtual bool eof() const;
|
||||
/*!
|
||||
@brief Returns a temporary data storage location. The actual type
|
||||
returned depends upon the size of the file represented a FileIo
|
||||
object. For small files, a MemIo is returned while for large files
|
||||
a FileIo is returned. Callers should not rely on this behavior,
|
||||
however, since it may change.
|
||||
@return An instance of BasicIo on success;<BR>
|
||||
Null pointer on failure;
|
||||
*/
|
||||
virtual BasicIo::AutoPtr temporary() const;
|
||||
//@}
|
||||
|
||||
private:
|
||||
// NOT IMPLEMENTED
|
||||
//! Copy constructor
|
||||
FileIo(FileIo& rhs);
|
||||
//! Assignment operator
|
||||
FileIo& operator=(const FileIo& rhs);
|
||||
|
||||
// Enumeration
|
||||
enum OpMode { opRead, opWrite, opSeek };
|
||||
|
||||
// DATA
|
||||
std::string path_;
|
||||
std::string openMode_;
|
||||
FILE *fp_;
|
||||
OpMode opMode_;
|
||||
}; // class FileIo
|
||||
|
||||
/*!
|
||||
@brief Provides binary IO on blocks of memory by implementing the
|
||||
BasicIo interface. The current implementation makes a copy of
|
||||
any data passed to its constructors. If writes are performed, the
|
||||
changed data can be retrieved using the read methods (since the
|
||||
data used in construction is never modified).
|
||||
|
||||
@note If read only usage of this class is common, it might be worth
|
||||
creating a specialized readonly class or changing this one to
|
||||
have a readonly mode.
|
||||
*/
|
||||
class MemIo : public BasicIo
|
||||
{
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Default constructor that results in an empty object
|
||||
MemIo() { idx_ = 0; }
|
||||
/*!
|
||||
@brief Constructor that accepts a block of memory to be copied.
|
||||
IO operations are performed on the copied memory.
|
||||
@param data Pointer to data. Data must be at least \em size
|
||||
bytes long
|
||||
@param size Number of bytes to copy.
|
||||
*/
|
||||
MemIo(const byte* data, long size);
|
||||
//! Destructor. Releases all managed memory
|
||||
virtual ~MemIo() {}
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Memory IO is always open for reading and writing. This method
|
||||
therefore only resets the IO position to the start.
|
||||
@return 0
|
||||
*/
|
||||
virtual int open();
|
||||
/*!
|
||||
@brief Does nothing on MemIo objects.
|
||||
@return 0
|
||||
*/
|
||||
virtual int close();
|
||||
/*!
|
||||
@brief Write data to the memory block. If needed, the size of the
|
||||
internal memory block is expanded. The IO position is advanced
|
||||
by the number of bytes written.
|
||||
@param data Pointer to data. Data must be at least \em wcount
|
||||
bytes long
|
||||
@param wcount Number of bytes to be written.
|
||||
@return Number of bytes written to the memory block successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(const byte* data, long wcount);
|
||||
/*!
|
||||
@brief Write data that is read from another BasicIo instance to
|
||||
the memory block. If needed, the size of the internal memory
|
||||
block is expanded. The IO position is advanced by the number
|
||||
of bytes written.
|
||||
@param src Reference to another BasicIo instance. Reading start
|
||||
at the source's current IO position
|
||||
@return Number of bytes written to the memory block successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long write(BasicIo& src);
|
||||
/*!
|
||||
@brief Write one byte to the memory block. The IO position is
|
||||
advanced by one byte.
|
||||
@param data The single byte to be written.
|
||||
@return The value of the byte written if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int putb(byte data);
|
||||
/*!
|
||||
@brief Read data from the memory block. Reading starts at the current
|
||||
IO position and the position is advanced by the number of
|
||||
bytes read.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return DataBuf instance containing the bytes read. Use the
|
||||
DataBuf::size_ member to find the number of bytes read.
|
||||
DataBuf::size_ will be 0 on failure.
|
||||
*/
|
||||
virtual DataBuf read(long rcount);
|
||||
/*!
|
||||
@brief Read data from the memory block. Reading starts at the current
|
||||
IO position and the position is advanced by the number of
|
||||
bytes read.
|
||||
@param buf Pointer to a block of memory into which the read data
|
||||
is stored. The memory block must be at least \em rcount bytes
|
||||
long.
|
||||
@param rcount Maximum number of bytes to read. Fewer bytes may be
|
||||
read if \em rcount bytes are not available.
|
||||
@return Number of bytes read from the memory block successfully;<BR>
|
||||
0 if failure;
|
||||
*/
|
||||
virtual long read(byte *buf, long rcount);
|
||||
/*!
|
||||
@brief Read one byte from the memory block. The IO position is
|
||||
advanced by one byte.
|
||||
@return The byte read from the memory block if successful;<BR>
|
||||
EOF if failure;
|
||||
*/
|
||||
virtual int getb();
|
||||
/*!
|
||||
@brief Clear the memory clock and then transfer data from
|
||||
the \em src BasicIo object into a new block of memory.
|
||||
|
||||
This method is optimized to simply swap memory block if the source
|
||||
object is another MemIo instance. The source BasicIo instance
|
||||
is invalidated by this operation and should not be used after this
|
||||
method returns. This method exists primarily to be used with
|
||||
the BasicIo::temporary() method.
|
||||
|
||||
@param src Reference to another BasicIo instance. The entire contents
|
||||
of src are transferred to this object. The \em src object is
|
||||
invalidated by the method.
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int transfer(BasicIo& src);
|
||||
/*!
|
||||
@brief Move the current IO position.
|
||||
@param offset Number of bytes to move the IO position
|
||||
relative to the starting position specified by \em pos
|
||||
@param pos Position from which the seek should start
|
||||
@return 0 if successful;<BR>
|
||||
Nonzero if failure;
|
||||
*/
|
||||
virtual int seek(long offset, Position pos);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Get the current IO position.
|
||||
@return Offset from the start of the memory block
|
||||
*/
|
||||
virtual long tell() const;
|
||||
//!Always returns true
|
||||
virtual bool isopen() const;
|
||||
//!Always returns 0
|
||||
virtual int error() const;
|
||||
//!Returns true if the IO position has reach the end, otherwise false.
|
||||
virtual bool eof() const;
|
||||
/*!
|
||||
@brief Returns a temporary data storage location. Currently returns
|
||||
an empty MemIo object, but callers should not rely on this
|
||||
behavior since it may change.
|
||||
@return An instance of BasicIo on success;<BR>
|
||||
Null pointer on failure;
|
||||
*/
|
||||
virtual BasicIo::AutoPtr temporary() const;
|
||||
//@}
|
||||
private:
|
||||
// NOT IMPLEMENTED
|
||||
//! Copy constructor
|
||||
MemIo(MemIo& rhs);
|
||||
//! Assignment operator
|
||||
MemIo& operator=(const MemIo& rhs);
|
||||
|
||||
// Typedefs
|
||||
typedef std::vector<byte> ByteVector;
|
||||
|
||||
// DATA
|
||||
ByteVector data_;
|
||||
ByteVector::size_type idx_;
|
||||
|
||||
//METHODS
|
||||
void checkSize(long wcount);
|
||||
}; // class MemIo
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef BASICIO_HPP_
|
@ -0,0 +1,217 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
/*
|
||||
Abstract : Tester application for BasicIo functions. Tests MemIo primarily
|
||||
since FileIo just sits atop of FILE* streams.
|
||||
|
||||
File : iotest.cpp
|
||||
Version : $Rev$
|
||||
Author(s): Brad Schick (brad) <brad@robotbattle.com>
|
||||
History : 13-Jul-04, brad: created
|
||||
*/
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "error.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include <iostream>
|
||||
|
||||
using Exiv2::byte;
|
||||
using Exiv2::BasicIo;
|
||||
using Exiv2::MemIo;
|
||||
using Exiv2::FileIo;
|
||||
using Exiv2::IoCloser;
|
||||
|
||||
int WriteReadSeek(BasicIo &io);
|
||||
|
||||
// *****************************************************************************
|
||||
// Main
|
||||
int main(int argc, char* const argv[])
|
||||
{
|
||||
try {
|
||||
if (argc != 4) {
|
||||
std::cout << "Usage: " << argv[0] << " filein fileout1 fileout2\n";
|
||||
std::cout << "fileouts are overwritten and should match filein exactly\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileIo fileIn(argv[1]);
|
||||
if (fileIn.open() != 0) {
|
||||
std::cerr << argv[0] <<
|
||||
": Could not open input file (" << argv[1] << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileIo fileOut1(argv[2]);
|
||||
if (fileOut1.open("w+b") != 0) {
|
||||
std::cerr << argv[0] <<
|
||||
": Could not open output file 1 (" << argv[2] << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
MemIo memIo1;
|
||||
|
||||
// Copy to output file through memIo
|
||||
memIo1.write(fileIn);
|
||||
memIo1.seek(0, BasicIo::beg);
|
||||
fileOut1.write(memIo1);
|
||||
|
||||
// Read writereadseek test on MemIo
|
||||
MemIo memIo2;
|
||||
int rc = WriteReadSeek(memIo2);
|
||||
if (rc != 0) return rc;
|
||||
|
||||
// Read writereadseek test on FileIo
|
||||
// Create or overwrite the file, then close it
|
||||
FileIo fileTest("iotest.txt");
|
||||
if (fileTest.open("w+b") != 0) {
|
||||
std::cerr << argv[0] <<
|
||||
": Could not create test file iotest.txt\n";
|
||||
return 1;
|
||||
}
|
||||
fileTest.close();
|
||||
rc = WriteReadSeek(fileTest);
|
||||
if (rc != 0) return rc;
|
||||
|
||||
// Another test of reading and writing
|
||||
fileOut1.seek(0, BasicIo::beg);
|
||||
memIo2.seek(0, BasicIo::beg);
|
||||
FileIo fileOut2(argv[3]);
|
||||
if (fileOut2.open("w+b") != 0) {
|
||||
std::cerr << argv[0] <<
|
||||
": Could not open output file 2 (" << argv[3] << ")\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
long readCount = 0;
|
||||
byte buf[32];
|
||||
while ((readCount=fileOut1.read(buf, sizeof(buf)))) {
|
||||
if (memIo2.write(buf, readCount) != readCount) {
|
||||
std::cerr << argv[0] <<
|
||||
": MemIo bad write 2\n";
|
||||
return 13;
|
||||
}
|
||||
if (fileOut2.write(buf, readCount) != readCount) {
|
||||
std::cerr << argv[0] <<
|
||||
": FileIo bad write 2\n";
|
||||
return 14;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch (Exiv2::Error& e) {
|
||||
std::cerr << "Caught Exiv2 exception '" << e << "'\n";
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int WriteReadSeek(BasicIo &io)
|
||||
{
|
||||
byte buf[4096];
|
||||
const char tester1[] = "this is a little test of MemIo";
|
||||
const char tester2[] = "Appending this on the end";
|
||||
const char expect[] = "this is a little teAppending this on the end";
|
||||
const long insert = 19;
|
||||
const long len1 = (long)strlen(tester1) + 1;
|
||||
const long len2 = (long)strlen(tester2) + 1;
|
||||
|
||||
IoCloser closer(io);
|
||||
if (io.open() != 0) {
|
||||
std::cerr << ": WRS could not open IO\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (io.write((byte*)tester1, len1) != len1) {
|
||||
std::cerr << ": WRS initial write failed\n";
|
||||
return 2;
|
||||
}
|
||||
io.seek(-len1, BasicIo::cur);
|
||||
|
||||
int c = EOF;
|
||||
memset(buf, -1, sizeof(buf));
|
||||
for (int i = 0; (c=io.getb()) != EOF; ++i) {
|
||||
buf[i] = (byte)c;
|
||||
}
|
||||
|
||||
// Make sure we got the null back
|
||||
if(buf[len1-1] != 0) {
|
||||
std::cerr << ": WRS missing null terminator 1\n";
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (strcmp(tester1, (char*)buf) != 0 ) {
|
||||
std::cerr << ": WRS strings don't match 1\n";
|
||||
return 4;
|
||||
}
|
||||
|
||||
io.seek(-2, BasicIo::end);
|
||||
if (io.getb() != 'o') {
|
||||
std::cerr << ": WRS bad getb o\n";
|
||||
return 5;
|
||||
}
|
||||
|
||||
io.seek(-2, BasicIo::cur);
|
||||
if (io.getb() != 'I') {
|
||||
std::cerr << ": WRS bad getb I\n";
|
||||
return 6;
|
||||
}
|
||||
|
||||
if (io.putb('O') != 'O') {
|
||||
std::cerr << ": WRS bad putb\n";
|
||||
return 7;
|
||||
}
|
||||
|
||||
io.seek(-1, BasicIo::cur);
|
||||
if (io.getb() != 'O') {
|
||||
std::cerr << ": WRS bad getb O\n";
|
||||
return 8;
|
||||
}
|
||||
|
||||
io.seek(insert, BasicIo::beg);
|
||||
if(io.write((byte*)tester2, len2) != len2) {
|
||||
std::cerr << ": WRS bad write 1\n";
|
||||
return 9;
|
||||
}
|
||||
|
||||
// open should seek to beginning
|
||||
io.open();
|
||||
memset(buf, -1, sizeof(buf));
|
||||
if (io.read(buf, sizeof(buf)) != insert + len2) {
|
||||
std::cerr << ": WRS something went wrong\n";
|
||||
return 10;
|
||||
}
|
||||
|
||||
// Make sure we got the null back
|
||||
if(buf[insert + len2 - 1] != 0) {
|
||||
std::cerr << ": WRS missing null terminator 2\n";
|
||||
return 11;
|
||||
}
|
||||
|
||||
if (strcmp(expect, (char*)buf) != 0 ) {
|
||||
std::cerr << ": WRS strings don't match 2\n";
|
||||
return 12;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,670 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
/*
|
||||
File: jpgimage.cpp
|
||||
Version: $Rev$
|
||||
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
|
||||
Brad Schick (brad) <brad@robotbattle.com>
|
||||
History: 15-Jan-05, brad: split out from image.cpp
|
||||
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Id$");
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#else
|
||||
# ifdef _MSC_VER
|
||||
# include <config_win32.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "jpgimage.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <cstring>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
|
||||
// Local functions. These could be static private functions on Image
|
||||
// subclasses but then ImageFactory needs to be made a friend.
|
||||
/*!
|
||||
@brief Create a new ExvImage instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create);
|
||||
//! Check if the file iIo is an EXV file
|
||||
bool isExvType(BasicIo& iIo, bool advance);
|
||||
/*!
|
||||
@brief Create a new JpegImage instance and return an auto-pointer to it.
|
||||
Caller owns the returned object and the auto-pointer ensures that
|
||||
it will be deleted.
|
||||
*/
|
||||
Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create);
|
||||
//! Check if the file iIo is a JPEG image.
|
||||
bool isJpegType(BasicIo& iIo, bool advance);
|
||||
|
||||
const byte JpegBase::sos_ = 0xda;
|
||||
const byte JpegBase::eoi_ = 0xd9;
|
||||
const byte JpegBase::app0_ = 0xe0;
|
||||
const byte JpegBase::app1_ = 0xe1;
|
||||
const byte JpegBase::app13_ = 0xed;
|
||||
const byte JpegBase::com_ = 0xfe;
|
||||
const uint16_t JpegBase::iptc_ = 0x0404;
|
||||
const char JpegBase::exifId_[] = "Exif\0\0";
|
||||
const char JpegBase::jfifId_[] = "JFIF\0";
|
||||
const char JpegBase::ps3Id_[] = "Photoshop 3.0\0";
|
||||
const char JpegBase::bimId_[] = "8BIM";
|
||||
|
||||
JpegBase::JpegBase(BasicIo::AutoPtr io, bool create,
|
||||
const byte initData[], long dataSize)
|
||||
: io_(io)
|
||||
{
|
||||
if (create) {
|
||||
initImage(initData, dataSize);
|
||||
}
|
||||
}
|
||||
|
||||
int JpegBase::initImage(const byte initData[], long dataSize)
|
||||
{
|
||||
IoCloser closer(*io_);
|
||||
if (io_->open() != 0) return 4;
|
||||
if (io_->write(initData, dataSize) != dataSize) {
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool JpegBase::good() const
|
||||
{
|
||||
IoCloser closer(*io_);
|
||||
if (io_->open() != 0) return false;
|
||||
return isThisType(*io_, false);
|
||||
}
|
||||
|
||||
void JpegBase::clearMetadata()
|
||||
{
|
||||
clearIptcData();
|
||||
clearExifData();
|
||||
clearComment();
|
||||
}
|
||||
|
||||
void JpegBase::clearIptcData()
|
||||
{
|
||||
iptcData_.clear();
|
||||
}
|
||||
|
||||
void JpegBase::clearExifData()
|
||||
{
|
||||
exifData_.clear();
|
||||
}
|
||||
|
||||
void JpegBase::clearComment()
|
||||
{
|
||||
comment_.erase();
|
||||
}
|
||||
|
||||
void JpegBase::setExifData(const ExifData& exifData)
|
||||
{
|
||||
exifData_ = exifData;
|
||||
}
|
||||
|
||||
void JpegBase::setIptcData(const IptcData& iptcData)
|
||||
{
|
||||
iptcData_ = iptcData;
|
||||
}
|
||||
|
||||
void JpegBase::setComment(const std::string& comment)
|
||||
{
|
||||
comment_ = comment;
|
||||
}
|
||||
|
||||
void JpegBase::setMetadata(const Image& image)
|
||||
{
|
||||
setIptcData(image.iptcData());
|
||||
setExifData(image.exifData());
|
||||
setComment(image.comment());
|
||||
}
|
||||
|
||||
int JpegBase::advanceToMarker() const
|
||||
{
|
||||
int c = -1;
|
||||
// Skips potential padding between markers
|
||||
while ((c=io_->getb()) != 0xff) {
|
||||
if (c == EOF) return -1;
|
||||
}
|
||||
|
||||
// Markers can start with any number of 0xff
|
||||
while ((c=io_->getb()) == 0xff) {
|
||||
if (c == EOF) return -1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int JpegBase::readMetadata()
|
||||
{
|
||||
IoCloser closer(*io_);
|
||||
if (io_->open() != 0) return 1;
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isThisType(*io_, true)) {
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
return 2;
|
||||
}
|
||||
clearMetadata();
|
||||
int search = 3;
|
||||
const long bufMinSize = 16;
|
||||
long bufRead = 0;
|
||||
DataBuf buf(bufMinSize);
|
||||
|
||||
// Read section marker
|
||||
int marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
|
||||
while (marker != sos_ && marker != eoi_ && search > 0) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = io_->read(buf.pData_, bufMinSize);
|
||||
if (io_->error()) return 1;
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
|
||||
if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
||||
if (size < 8) return 2;
|
||||
// Seek to begining and read the Exif data
|
||||
io_->seek(8-bufRead, BasicIo::cur);
|
||||
long sizeExifData = size - 8;
|
||||
DataBuf rawExif(sizeExifData);
|
||||
io_->read(rawExif.pData_, sizeExifData);
|
||||
if (io_->error() || io_->eof()) {
|
||||
return 1;
|
||||
}
|
||||
if (exifData_.load(rawExif.pData_, sizeExifData)) return 2;
|
||||
--search;
|
||||
}
|
||||
else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
|
||||
if (size < 16) return 2;
|
||||
// Read the rest of the APP13 segment
|
||||
// needed if bufMinSize!=16: io_->seek(16-bufRead, BasicIo::cur);
|
||||
DataBuf psData(size - 16);
|
||||
io_->read(psData.pData_, psData.size_);
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
const byte *record = 0;
|
||||
uint16_t sizeIptc = 0;
|
||||
uint16_t sizeHdr = 0;
|
||||
// Find actual Iptc data within the APP13 segment
|
||||
if (!locateIptcData(psData.pData_, psData.size_, &record,
|
||||
&sizeHdr, &sizeIptc)) {
|
||||
assert(sizeIptc);
|
||||
if (iptcData_.load(record + sizeHdr, sizeIptc)) return 2;
|
||||
}
|
||||
--search;
|
||||
}
|
||||
else if (marker == com_ && comment_.empty())
|
||||
{
|
||||
if (size < 2) return 2;
|
||||
// Jpegs can have multiple comments, but for now only read
|
||||
// the first one (most jpegs only have one anyway). Comments
|
||||
// are simple single byte ISO-8859-1 strings.
|
||||
io_->seek(2-bufRead, BasicIo::cur);
|
||||
buf.alloc(size-2);
|
||||
io_->read(buf.pData_, size-2);
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
comment_.assign(reinterpret_cast<char*>(buf.pData_), size-2);
|
||||
while ( comment_.length()
|
||||
&& comment_.at(comment_.length()-1) == '\0') {
|
||||
comment_.erase(comment_.length()-1);
|
||||
}
|
||||
--search;
|
||||
}
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
// Skip the remainder of the unknown segment
|
||||
if (io_->seek(size-bufRead, BasicIo::cur)) return 2;
|
||||
}
|
||||
// Read the beginning of the next segment
|
||||
marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
}
|
||||
return 0;
|
||||
} // JpegBase::readMetadata
|
||||
|
||||
|
||||
// Operates on raw data (rather than file streams) to simplify reuse
|
||||
int JpegBase::locateIptcData(const byte *pPsData,
|
||||
long sizePsData,
|
||||
const byte **record,
|
||||
uint16_t *const sizeHdr,
|
||||
uint16_t *const sizeIptc) const
|
||||
{
|
||||
assert(record);
|
||||
assert(sizeHdr);
|
||||
assert(sizeIptc);
|
||||
// Used for error checking
|
||||
long position = 0;
|
||||
|
||||
// Data should follow Photoshop format, if not exit
|
||||
while (position <= (sizePsData - 14) &&
|
||||
memcmp(pPsData + position, bimId_, 4)==0) {
|
||||
const byte *hrd = pPsData + position;
|
||||
position += 4;
|
||||
uint16_t type = getUShort(pPsData+ position, bigEndian);
|
||||
position += 2;
|
||||
|
||||
// Pascal string is padded to have an even size (including size byte)
|
||||
byte psSize = pPsData[position] + 1;
|
||||
psSize += (psSize & 1);
|
||||
position += psSize;
|
||||
if (position >= sizePsData) return -2;
|
||||
|
||||
// Data is also padded to be even
|
||||
long dataSize = getULong(pPsData + position, bigEndian);
|
||||
position += 4;
|
||||
if (dataSize > sizePsData - position) return -2;
|
||||
|
||||
if (type == iptc_) {
|
||||
*sizeIptc = static_cast<uint16_t>(dataSize);
|
||||
*sizeHdr = psSize + 10;
|
||||
*record = hrd;
|
||||
return 0;
|
||||
}
|
||||
position += dataSize + (dataSize & 1);
|
||||
}
|
||||
return 3;
|
||||
} // JpegBase::locateIptcData
|
||||
|
||||
int JpegBase::writeMetadata()
|
||||
{
|
||||
IoCloser closer(*io_);
|
||||
if (io_->open() != 0) return 1;
|
||||
BasicIo::AutoPtr tempIo(io_->temporary());
|
||||
if (!tempIo.get()) return -3;
|
||||
|
||||
int rc = doWriteMetadata(*tempIo);
|
||||
io_->close();
|
||||
if( rc == 0 ) {
|
||||
if (io_->transfer(*tempIo) != 0) return -3;
|
||||
}
|
||||
return rc;
|
||||
} // JpegBase::writeMetadata
|
||||
|
||||
int JpegBase::doWriteMetadata(BasicIo& outIo)
|
||||
{
|
||||
if (!io_->isopen()) return 1;
|
||||
if (!outIo.isopen()) return 4;
|
||||
|
||||
// Ensure that this is the correct image type
|
||||
if (!isThisType(*io_, true)) {
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
return 2;
|
||||
}
|
||||
|
||||
const long bufMinSize = 16;
|
||||
long bufRead = 0;
|
||||
DataBuf buf(bufMinSize);
|
||||
const long seek = io_->tell();
|
||||
int count = 0;
|
||||
int search = 0;
|
||||
int insertPos = 0;
|
||||
int skipApp1Exif = -1;
|
||||
int skipApp13Ps3 = -1;
|
||||
int skipCom = -1;
|
||||
DataBuf psData;
|
||||
|
||||
// Write image header
|
||||
if (writeHeader(outIo)) return 4;
|
||||
|
||||
// Read section marker
|
||||
int marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
|
||||
// First find segments of interest. Normally app0 is first and we want
|
||||
// to insert after it. But if app0 comes after com, app1 and app13 then
|
||||
// don't bother.
|
||||
while (marker != sos_ && marker != eoi_ && search < 3) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = io_->read(buf.pData_, bufMinSize);
|
||||
if (io_->error()) return 1;
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
|
||||
if (marker == app0_) {
|
||||
if (size < 2) return 2;
|
||||
insertPos = count + 1;
|
||||
if (io_->seek(size-bufRead, BasicIo::cur)) return 2;
|
||||
}
|
||||
else if (marker == app1_ && memcmp(buf.pData_ + 2, exifId_, 6) == 0) {
|
||||
if (size < 8) return 2;
|
||||
skipApp1Exif = count;
|
||||
++search;
|
||||
if (io_->seek(size-bufRead, BasicIo::cur)) return 2;
|
||||
}
|
||||
else if (marker == app13_ && memcmp(buf.pData_ + 2, ps3Id_, 14) == 0) {
|
||||
if (size < 16) return 2;
|
||||
skipApp13Ps3 = count;
|
||||
++search;
|
||||
// needed if bufMinSize!=16: io_->seek(16-bufRead, BasicIo::cur);
|
||||
psData.alloc(size - 16);
|
||||
// Load PS data now to allow reinsertion at any point
|
||||
io_->read(psData.pData_, psData.size_);
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
}
|
||||
else if (marker == com_ && skipCom == -1) {
|
||||
if (size < 2) return 2;
|
||||
// Jpegs can have multiple comments, but for now only handle
|
||||
// the first one (most jpegs only have one anyway).
|
||||
skipCom = count;
|
||||
++search;
|
||||
if (io_->seek(size-bufRead, BasicIo::cur)) return 2;
|
||||
}
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
if (io_->seek(size-bufRead, BasicIo::cur)) return 2;
|
||||
}
|
||||
marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
++count;
|
||||
}
|
||||
|
||||
if (exifData_.count() > 0) ++search;
|
||||
if (iptcData_.count() > 0) ++search;
|
||||
if (!comment_.empty()) ++search;
|
||||
|
||||
io_->seek(seek, BasicIo::beg);
|
||||
count = 0;
|
||||
marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
|
||||
// To simplify this a bit, new segments are inserts at either the start
|
||||
// or right after app0. This is standard in most jpegs, but has the
|
||||
// potential to change segment ordering (which is allowed).
|
||||
// Segments are erased if there is no assigned metadata.
|
||||
while (marker != sos_ && search > 0) {
|
||||
// Read size and signature (ok if this hits EOF)
|
||||
bufRead = io_->read(buf.pData_, bufMinSize);
|
||||
if (io_->error()) return 1;
|
||||
// Careful, this can be a meaningless number for empty
|
||||
// images with only an eoi_ marker
|
||||
uint16_t size = getUShort(buf.pData_, bigEndian);
|
||||
|
||||
if (insertPos == count) {
|
||||
byte tmpBuf[18];
|
||||
if (!comment_.empty()) {
|
||||
// Write COM marker, size of comment, and string
|
||||
tmpBuf[0] = 0xff;
|
||||
tmpBuf[1] = com_;
|
||||
us2Data(tmpBuf + 2,
|
||||
static_cast<uint16_t>(comment_.length()+3), bigEndian);
|
||||
if (outIo.write(tmpBuf, 4) != 4) return 4;
|
||||
if (outIo.write((byte*)comment_.data(), (long)comment_.length())
|
||||
!= (long)comment_.length()) return 4;
|
||||
if (outIo.putb(0)==EOF) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
--search;
|
||||
}
|
||||
if (exifData_.count() > 0) {
|
||||
// Write APP1 marker, size of APP1 field, Exif id and Exif data
|
||||
DataBuf rawExif(exifData_.copy());
|
||||
tmpBuf[0] = 0xff;
|
||||
tmpBuf[1] = app1_;
|
||||
us2Data(tmpBuf + 2,
|
||||
static_cast<uint16_t>(rawExif.size_+8),
|
||||
bigEndian);
|
||||
memcpy(tmpBuf + 4, exifId_, 6);
|
||||
if (outIo.write(tmpBuf, 10) != 10) return 4;
|
||||
if (outIo.write(rawExif.pData_, rawExif.size_)
|
||||
!= rawExif.size_) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
--search;
|
||||
}
|
||||
|
||||
const byte *record = psData.pData_;
|
||||
uint16_t sizeIptc = 0;
|
||||
uint16_t sizeHdr = 0;
|
||||
// Safe to call with zero psData.size_
|
||||
locateIptcData(psData.pData_, psData.size_, &record, &sizeHdr, &sizeIptc);
|
||||
|
||||
// Data is rounded to be even
|
||||
const int sizeOldData = sizeHdr + sizeIptc + (sizeIptc & 1);
|
||||
if (psData.size_ > sizeOldData || iptcData_.count() > 0) {
|
||||
// rawIptc may have size of zero.
|
||||
DataBuf rawIptc(iptcData_.copy());
|
||||
// write app13 marker, new size, and ps3Id
|
||||
tmpBuf[0] = 0xff;
|
||||
tmpBuf[1] = app13_;
|
||||
const int sizeNewData = rawIptc.size_ ?
|
||||
rawIptc.size_ + (rawIptc.size_ & 1) + 12 : 0;
|
||||
us2Data(tmpBuf + 2,
|
||||
static_cast<uint16_t>(psData.size_-sizeOldData+sizeNewData+16),
|
||||
bigEndian);
|
||||
memcpy(tmpBuf + 4, ps3Id_, 14);
|
||||
if (outIo.write(tmpBuf, 18) != 18) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
|
||||
const long sizeFront = (long)(record - psData.pData_);
|
||||
const long sizeEnd = psData.size_ - sizeFront - sizeOldData;
|
||||
// write data before old record.
|
||||
if (outIo.write(psData.pData_, sizeFront) != sizeFront) return 4;
|
||||
|
||||
// write new iptc record if we have it
|
||||
if (iptcData_.count() > 0) {
|
||||
memcpy(tmpBuf, bimId_, 4);
|
||||
us2Data(tmpBuf+4, iptc_, bigEndian);
|
||||
tmpBuf[6] = 0;
|
||||
tmpBuf[7] = 0;
|
||||
ul2Data(tmpBuf + 8, rawIptc.size_, bigEndian);
|
||||
if (outIo.write(tmpBuf, 12) != 12) return 4;
|
||||
if (outIo.write(rawIptc.pData_, rawIptc.size_)
|
||||
!= rawIptc.size_) return 4;
|
||||
// data is padded to be even (but not included in size)
|
||||
if (rawIptc.size_ & 1) {
|
||||
if (outIo.putb(0)==EOF) return 4;
|
||||
}
|
||||
if (outIo.error()) return 4;
|
||||
--search;
|
||||
}
|
||||
|
||||
// write existing stuff after record
|
||||
if (outIo.write(record+sizeOldData, sizeEnd)
|
||||
!= sizeEnd) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
}
|
||||
}
|
||||
if (marker == eoi_) {
|
||||
break;
|
||||
}
|
||||
else if (skipApp1Exif==count || skipApp13Ps3==count || skipCom==count) {
|
||||
--search;
|
||||
io_->seek(size-bufRead, BasicIo::cur);
|
||||
}
|
||||
else {
|
||||
if (size < 2) return 2;
|
||||
buf.alloc(size+2);
|
||||
io_->seek(-bufRead-2, BasicIo::cur);
|
||||
io_->read(buf.pData_, size+2);
|
||||
if (io_->error() || io_->eof()) return 1;
|
||||
if (outIo.write(buf.pData_, size+2) != size+2) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
}
|
||||
|
||||
// Next marker
|
||||
marker = advanceToMarker();
|
||||
if (marker < 0) return 2;
|
||||
++count;
|
||||
}
|
||||
|
||||
// Copy rest of the Io
|
||||
io_->seek(-2, BasicIo::cur);
|
||||
buf.alloc(4096);
|
||||
long readSize = 0;
|
||||
while ((readSize=io_->read(buf.pData_, buf.size_))) {
|
||||
if (outIo.write(buf.pData_, readSize) != readSize) return 4;
|
||||
}
|
||||
if (outIo.error()) return 4;
|
||||
|
||||
return 0;
|
||||
}// JpegBase::doWriteMetadata
|
||||
|
||||
|
||||
const byte JpegImage::soi_ = 0xd8;
|
||||
const byte JpegImage::blank_[] = {
|
||||
0xFF,0xD8,0xFF,0xDB,0x00,0x84,0x00,0x10,0x0B,0x0B,0x0B,0x0C,0x0B,0x10,0x0C,0x0C,
|
||||
0x10,0x17,0x0F,0x0D,0x0F,0x17,0x1B,0x14,0x10,0x10,0x14,0x1B,0x1F,0x17,0x17,0x17,
|
||||
0x17,0x17,0x1F,0x1E,0x17,0x1A,0x1A,0x1A,0x1A,0x17,0x1E,0x1E,0x23,0x25,0x27,0x25,
|
||||
0x23,0x1E,0x2F,0x2F,0x33,0x33,0x2F,0x2F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x01,0x11,0x0F,0x0F,0x11,0x13,0x11,0x15,0x12,
|
||||
0x12,0x15,0x14,0x11,0x14,0x11,0x14,0x1A,0x14,0x16,0x16,0x14,0x1A,0x26,0x1A,0x1A,
|
||||
0x1C,0x1A,0x1A,0x26,0x30,0x23,0x1E,0x1E,0x1E,0x1E,0x23,0x30,0x2B,0x2E,0x27,0x27,
|
||||
0x27,0x2E,0x2B,0x35,0x35,0x30,0x30,0x35,0x35,0x40,0x40,0x3F,0x40,0x40,0x40,0x40,
|
||||
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0xFF,0xC0,0x00,0x11,0x08,0x00,0x01,0x00,
|
||||
0x01,0x03,0x01,0x22,0x00,0x02,0x11,0x01,0x03,0x11,0x01,0xFF,0xC4,0x00,0x4B,0x00,
|
||||
0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x07,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x10,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x11,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xDA,0x00,0x0C,0x03,0x01,0x00,0x02,
|
||||
0x11,0x03,0x11,0x00,0x3F,0x00,0xA0,0x00,0x0F,0xFF,0xD9 };
|
||||
|
||||
JpegImage::JpegImage(BasicIo::AutoPtr io, bool create)
|
||||
: JpegBase(io, create, blank_, sizeof(blank_))
|
||||
{
|
||||
}
|
||||
|
||||
//! @cond IGNORE
|
||||
JpegImage::JpegRegister::JpegRegister()
|
||||
{
|
||||
ImageFactory::registerImage(
|
||||
Image::jpeg, newJpegInstance, isJpegType);
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
int JpegImage::writeHeader(BasicIo& outIo) const
|
||||
{
|
||||
// Jpeg header
|
||||
byte tmpBuf[2];
|
||||
tmpBuf[0] = 0xff;
|
||||
tmpBuf[1] = soi_;
|
||||
if (outIo.write(tmpBuf, 2) != 2) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool JpegImage::isThisType(BasicIo& iIo, bool advance) const
|
||||
{
|
||||
return isJpegType(iIo, advance);
|
||||
}
|
||||
|
||||
Image::AutoPtr newJpegInstance(BasicIo::AutoPtr io, bool create)
|
||||
{
|
||||
Image::AutoPtr image;
|
||||
if (create) {
|
||||
image = Image::AutoPtr(new JpegImage(io, true));
|
||||
}
|
||||
else {
|
||||
image = Image::AutoPtr(new JpegImage(io, false));
|
||||
}
|
||||
if (!image->good()) {
|
||||
image.reset();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool isJpegType(BasicIo& iIo, bool advance)
|
||||
{
|
||||
bool result = true;
|
||||
byte tmpBuf[2];
|
||||
iIo.read(tmpBuf, 2);
|
||||
if (iIo.error() || iIo.eof()) return false;
|
||||
|
||||
if (0xff!=tmpBuf[0] || JpegImage::soi_!=tmpBuf[1]) {
|
||||
result = false;
|
||||
}
|
||||
if (!advance || !result ) iIo.seek(-2, BasicIo::cur);
|
||||
return result;
|
||||
}
|
||||
|
||||
const char ExvImage::exiv2Id_[] = "Exiv2";
|
||||
const byte ExvImage::blank_[] = { 0xff,0x01,'E','x','i','v','2',0xff,0xd9 };
|
||||
|
||||
ExvImage::ExvImage(BasicIo::AutoPtr io, bool create)
|
||||
: JpegBase(io, create, blank_, sizeof(blank_))
|
||||
{
|
||||
}
|
||||
|
||||
//! @cond IGNORE
|
||||
ExvImage::ExvRegister::ExvRegister()
|
||||
{
|
||||
ImageFactory::registerImage(
|
||||
Image::exv, newExvInstance, isExvType);
|
||||
}
|
||||
//! @endcond
|
||||
|
||||
int ExvImage::writeHeader(BasicIo& outIo) const
|
||||
{
|
||||
// Exv header
|
||||
byte tmpBuf[7];
|
||||
tmpBuf[0] = 0xff;
|
||||
tmpBuf[1] = 0x01;
|
||||
memcpy(tmpBuf + 2, exiv2Id_, 5);
|
||||
if (outIo.write(tmpBuf, 7) != 7) return 4;
|
||||
if (outIo.error()) return 4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ExvImage::isThisType(BasicIo& iIo, bool advance) const
|
||||
{
|
||||
return isExvType(iIo, advance);
|
||||
}
|
||||
|
||||
Image::AutoPtr newExvInstance(BasicIo::AutoPtr io, bool create)
|
||||
{
|
||||
Image::AutoPtr image;
|
||||
if (create) {
|
||||
image = Image::AutoPtr(new ExvImage(io, true));
|
||||
}
|
||||
else {
|
||||
image = Image::AutoPtr(new ExvImage(io, false));
|
||||
}
|
||||
if (!image->good()) image.reset();
|
||||
return image;
|
||||
}
|
||||
|
||||
bool isExvType(BasicIo& iIo, bool advance)
|
||||
{
|
||||
bool result = true;
|
||||
byte tmpBuf[7];
|
||||
iIo.read(tmpBuf, 7);
|
||||
if (iIo.error() || iIo.eof()) return false;
|
||||
|
||||
if (0xff!=tmpBuf[0] || 0x01!=tmpBuf[1] ||
|
||||
memcmp(tmpBuf + 2, ExvImage::exiv2Id_, 5) != 0) {
|
||||
result = false;
|
||||
}
|
||||
if (!advance || !result ) iIo.seek(-7, BasicIo::cur);
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Exiv2
|
@ -0,0 +1,418 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2004 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* This program is part of the Exiv2 distribution.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
/*!
|
||||
@file jpgimage.hpp
|
||||
@brief Class JpegImage to access JPEG images
|
||||
@version $Rev$
|
||||
@author Andreas Huggel (ahu)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@author Brad Schick (brad)
|
||||
<a href="mailto:brad@robotbattle.com">brad@robotbattle.com</a>
|
||||
@date 15-Jan-05, brad: split out from image.cpp
|
||||
*/
|
||||
#ifndef JPGIMAGE_HPP_
|
||||
#define JPGIMAGE_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
#include "image.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include "exif.hpp"
|
||||
#include "iptc.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
/*!
|
||||
@brief Abstract helper base class to access JPEG images.
|
||||
*/
|
||||
class JpegBase : public Image {
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
//! Virtual destructor.
|
||||
virtual ~JpegBase() {}
|
||||
//@}
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Read all metadata from the image. Before this method
|
||||
is called, the various metadata types (Iptc, Exif) will be empty.
|
||||
|
||||
This method returns success even when no metadata is found in
|
||||
the image. Callers must therefore check the size of indivdual
|
||||
metadata types before accessing the data.
|
||||
|
||||
@return 0 if successful;<BR>
|
||||
1 if reading from the file failed
|
||||
(could be caused by invalid image);<BR>
|
||||
2 if the file does not contain a valid image;<BR>
|
||||
*/
|
||||
int readMetadata();
|
||||
/*!
|
||||
@brief Write metadata back to the image.
|
||||
|
||||
All existing metadata sections in the image are either created,
|
||||
replaced, or erased. If values for a given metadata type have been
|
||||
assigned, a section for that metadata type will either be created or
|
||||
replaced. If no values have been assigned to a given metadata type,
|
||||
any exists section for that metadata type will be removed from the
|
||||
image.
|
||||
|
||||
@return 0 if successful;<br>
|
||||
1 if reading from the file failed;<BR>
|
||||
2 if the file does not contain a valid image;<BR>
|
||||
4 if the temporary output file can not be written to;<BR>
|
||||
-1 if the newly created file could not be reopened;<BR>
|
||||
-3 if the temporary output file can not be opened;<BR>
|
||||
-4 if renaming the temporary file fails;<br>
|
||||
*/
|
||||
int writeMetadata();
|
||||
/*!
|
||||
@brief Assign new exif data. The new exif data is not written
|
||||
to the image until the writeMetadata() method is called.
|
||||
@param exifData An ExifData instance holding exif data to be copied
|
||||
|
||||
@throw Error ("Exif data too large") if the exif data is larger than
|
||||
65535 bytes (the maximum size of JPEG APP segments)
|
||||
*/
|
||||
void setExifData(const ExifData& exifData);
|
||||
void clearExifData();
|
||||
void setIptcData(const IptcData& iptcData);
|
||||
void clearIptcData();
|
||||
void setComment(const std::string& comment);
|
||||
void clearComment();
|
||||
void setMetadata(const Image& image);
|
||||
void clearMetadata();
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
bool good() const;
|
||||
const ExifData& exifData() const { return exifData_; }
|
||||
ExifData& exifData() { return exifData_; }
|
||||
const IptcData& iptcData() const { return iptcData_; }
|
||||
IptcData& iptcData() { return iptcData_; }
|
||||
std::string comment() const { return comment_; }
|
||||
BasicIo& io() const { return *io_; }
|
||||
//@}
|
||||
protected:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor that can either open an existing image or create
|
||||
a new image from scratch. If a new image is to be created, any
|
||||
existing data is overwritten.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
@param create Specifies if an existing image should be read (false)
|
||||
or if a new image should be created (true).
|
||||
@param initData Data to initialize newly created images. Only used
|
||||
when \em create is true. Should contain data for the smallest
|
||||
valid image of the calling subclass.
|
||||
@param dataSize Size of initData in bytes.
|
||||
*/
|
||||
JpegBase(BasicIo::AutoPtr io, bool create,
|
||||
const byte initData[], long dataSize);
|
||||
//@}
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Writes the image header (aka signature) to the BasicIo instance.
|
||||
@param oIo BasicIo instance that the header is written to.
|
||||
@return 0 if successful;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
virtual int writeHeader(BasicIo& oIo) const =0;
|
||||
//@}
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Determine if the content of the BasicIo instance is of the
|
||||
type supported by this class.
|
||||
|
||||
The advance flag determines if the read position in the stream is
|
||||
moved (see below). This applies only if the type matches and the
|
||||
function returns true. If the type does not match, the stream
|
||||
position is not changed. However, if reading from the stream fails,
|
||||
the stream position is undefined. Consult the stream state to obtain
|
||||
more information in this case.
|
||||
|
||||
@param iIo BasicIo instance to read from.
|
||||
@param advance Flag indicating whether the position of the io
|
||||
should be advanced by the number of characters read to
|
||||
analyse the data (true) or left at its original
|
||||
position (false). This applies only if the type matches.
|
||||
@return true if the data matches the type of this class;<BR>
|
||||
false if the data does not match;<BR>
|
||||
*/
|
||||
virtual bool isThisType(BasicIo& iIo, bool advance) const =0;
|
||||
//@}
|
||||
|
||||
// Constant Data
|
||||
static const byte sos_; //!< JPEG SOS marker
|
||||
static const byte eoi_; //!< JPEG EOI marker
|
||||
static const byte app0_; //!< JPEG APP0 marker
|
||||
static const byte app1_; //!< JPEG APP1 marker
|
||||
static const byte app13_; //!< JPEG APP13 marker
|
||||
static const byte com_; //!< JPEG Comment marker
|
||||
static const char exifId_[]; //!< Exif identifier
|
||||
static const char jfifId_[]; //!< JFIF identifier
|
||||
static const char ps3Id_[]; //!< Photoshop marker
|
||||
static const char bimId_[]; //!< Photoshop marker
|
||||
static const uint16_t iptc_; //!< Photoshop Iptc marker
|
||||
|
||||
private:
|
||||
// DATA
|
||||
BasicIo::AutoPtr io_; //!< Image data io pointer
|
||||
ExifData exifData_; //!< Exif data container
|
||||
IptcData iptcData_; //!< Iptc data container
|
||||
std::string comment_; //!< JPEG comment
|
||||
|
||||
// METHODS
|
||||
/*!
|
||||
@brief Advances associated io instance to one byte past the next
|
||||
Jpeg marker and returns the marker. This method should be called
|
||||
when the BasicIo instance is positioned one byte past the end of a
|
||||
Jpeg segment.
|
||||
@return the next Jpeg segment marker if successful;<BR>
|
||||
-1 if a maker was not found before EOF;<BR>
|
||||
*/
|
||||
int advanceToMarker() const;
|
||||
/*!
|
||||
@brief Locates Photoshop formated Iptc data in a memory buffer.
|
||||
Operates on raw data to simplify reuse.
|
||||
@param pPsData Pointer to buffer containing entire payload of
|
||||
Photoshop formated APP13 Jpeg segment.
|
||||
@param sizePsData Size in bytes of pPsData.
|
||||
@param record Output value that is set to the start of the Iptc
|
||||
data block within pPsData (may not be null).
|
||||
@param sizeHdr Output value that is set to the size of the header
|
||||
within the Iptc data block pointed to by record (may not
|
||||
be null).
|
||||
@param sizeIptc Output value that is set to the size of the actual
|
||||
Iptc data within the Iptc data block pointed to by record
|
||||
(may not be null).
|
||||
@return 0 if successful;<BR>
|
||||
3 if no Iptc data was found in pPsData;<BR>
|
||||
-2 if the pPsData buffer does not contain valid data;<BR>
|
||||
*/
|
||||
int locateIptcData(const byte *pPsData,
|
||||
long sizePsData,
|
||||
const byte **record,
|
||||
uint16_t *const sizeHdr,
|
||||
uint16_t *const sizeIptc) const;
|
||||
/*!
|
||||
@brief Initialize the image with the provided data.
|
||||
@param initData Data to be written to the associated BasicIo
|
||||
@param dataSize Size in bytes of data to be written
|
||||
@return 0 if successful;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
int initImage(const byte initData[], long dataSize);
|
||||
/*!
|
||||
@brief Provides the main implementation of writeMetadata() by
|
||||
writing all buffered metadata to the provided BasicIo.
|
||||
@param oIo BasicIo instance to write to (a temporary location).
|
||||
@return 0 if successful;<br>
|
||||
1 if reading from input file failed;<BR>
|
||||
2 if the input file does not contain a valid image;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
int doWriteMetadata(BasicIo& oIo);
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor.
|
||||
JpegBase();
|
||||
//! Copy constructor
|
||||
JpegBase(const JpegBase& rhs);
|
||||
//! Assignment operator
|
||||
JpegBase& operator=(const JpegBase& rhs);
|
||||
}; // class JpegBase
|
||||
|
||||
/*!
|
||||
@brief Class to access JPEG images
|
||||
*/
|
||||
class JpegImage : public JpegBase {
|
||||
friend bool isJpegType(BasicIo& iIo, bool advance);
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor that can either open an existing Jpeg image or create
|
||||
a new image from scratch. If a new image is to be created, any
|
||||
existing data is overwritten. Since the constructor can not return
|
||||
a result, callers should check the good() method after object
|
||||
construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
@param create Specifies if an existing image should be read (false)
|
||||
or if a new file should be created (true).
|
||||
*/
|
||||
JpegImage(BasicIo::AutoPtr io, bool create);
|
||||
//! Destructor
|
||||
~JpegImage() {}
|
||||
//@}
|
||||
|
||||
//! @cond IGNORE
|
||||
// Public only so that we can create a static instance
|
||||
struct JpegRegister{
|
||||
JpegRegister();
|
||||
};
|
||||
//! @endcond
|
||||
protected:
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Determine if the content of the BasicIo instance is a Jpeg image.
|
||||
See base class for more details.
|
||||
@param iIo BasicIo instance to read from.
|
||||
@param advance Flag indicating whether the position of the io
|
||||
should be advanced by the number of characters read to
|
||||
analyse the data (true) or left at its original
|
||||
position (false). This applies only if the type matches.
|
||||
@return true if the data matches a Jpeg image;<BR>
|
||||
false if the data does not match;<BR>
|
||||
*/
|
||||
bool isThisType(BasicIo& iIo, bool advance) const;
|
||||
//@}
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Writes a Jpeg header (aka signature) to the BasicIo instance.
|
||||
@param oIo BasicIo instance that the header is written to.
|
||||
@return 0 if successful;<BR>
|
||||
2 if the input image is invalid or can not be read;<BR>
|
||||
4 if the temporary image can not be written to;<BR>
|
||||
-3 other temporary errors;<BR>
|
||||
*/
|
||||
int writeHeader(BasicIo& oIo) const;
|
||||
//@}
|
||||
private:
|
||||
// Constant data
|
||||
static const byte soi_; // SOI marker
|
||||
static const byte blank_[]; // Minimal Jpeg image
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor
|
||||
JpegImage();
|
||||
//! Copy constructor
|
||||
JpegImage(const JpegImage& rhs);
|
||||
//! Assignment operator
|
||||
JpegImage& operator=(const JpegImage& rhs);
|
||||
}; // class JpegImage
|
||||
|
||||
static JpegImage::JpegRegister jpegReg;
|
||||
|
||||
//! Helper class to access %Exiv2 files
|
||||
class ExvImage : public JpegBase {
|
||||
friend bool isExvType(BasicIo& iIo, bool advance);
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor that can either open an existing Exv image or create
|
||||
a new image from scratch. If a new image is to be created, any
|
||||
existing data is overwritten. Since the constructor can not return
|
||||
a result, callers should check the good() method after object
|
||||
construction to determine success or failure.
|
||||
@param io An auto-pointer that owns a BasicIo instance used for
|
||||
reading and writing image metadata. \b Important: The constructor
|
||||
takes ownership of the passed in BasicIo instance through the
|
||||
auto-pointer. Callers should not continue to use the BasicIo
|
||||
instance after it is passed to this method. Use the Image::io()
|
||||
method to get a temporary reference.
|
||||
@param create Specifies if an existing image should be read (false)
|
||||
or if a new file should be created (true).
|
||||
*/
|
||||
ExvImage(BasicIo::AutoPtr io, bool create);
|
||||
//! Destructor
|
||||
~ExvImage() {}
|
||||
//@}
|
||||
|
||||
//! @cond IGNORE
|
||||
// Public only so that we can create a static instance
|
||||
struct ExvRegister{
|
||||
ExvRegister();
|
||||
};
|
||||
//! @endcond
|
||||
protected:
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Determine if the content of the BasicIo instance is an Exv
|
||||
image. See base class for more details.
|
||||
@param iIo BasicIo instance to read from.
|
||||
@param advance Flag indicating whether the position of the io
|
||||
should be advanced by the number of characters read to
|
||||
analyse the data (true) or left at its original
|
||||
position (false). This applies only if the type matches.
|
||||
@return true if the data matches a Jpeg image;<BR>
|
||||
false if the data does not match;<BR>
|
||||
*/
|
||||
virtual bool isThisType(BasicIo& iIo, bool advance) const;
|
||||
//@}
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
/*!
|
||||
@brief Writes an Exv header (aka signature) to the BasicIo instance.
|
||||
@param oIo BasicIo instance that the header is written to.
|
||||
@return 0 if successful;<BR>
|
||||
4 if the output file can not be written to;<BR>
|
||||
*/
|
||||
int writeHeader(BasicIo& oIo) const;
|
||||
//@}
|
||||
private:
|
||||
// Constant data
|
||||
static const char exiv2Id_[]; // Exv identifier
|
||||
static const byte blank_[]; // Minimal exiv file
|
||||
|
||||
// NOT Implemented
|
||||
//! Default constructor
|
||||
ExvImage();
|
||||
//! Copy constructor
|
||||
ExvImage(const ExvImage& rhs);
|
||||
//! Assignment operator
|
||||
ExvImage& operator=(const ExvImage& rhs);
|
||||
}; // class ExvImage
|
||||
|
||||
static ExvImage::ExvRegister exvReg;
|
||||
} // namespace Exiv2
|
||||
|
||||
|
||||
#endif // #ifndef JPGIMAGE_HPP_
|
@ -1 +0,0 @@
|
||||
Caught Exiv2 exception 'temp: No Iptc data found in the file'
|
@ -0,0 +1,59 @@
|
||||
#! /bin/bash
|
||||
# Test driver for image file i/o
|
||||
|
||||
ioTest()
|
||||
{
|
||||
src=$datapath/$1
|
||||
out1=${1}.1
|
||||
out2=${1}.2
|
||||
|
||||
#run tests
|
||||
$binpath/iotest $src $out1 $out2
|
||||
if [ $? -ne 0 ]; then
|
||||
let ++errors
|
||||
return
|
||||
fi
|
||||
|
||||
#check results
|
||||
diffCheck $out1 $src
|
||||
diffCheck $out2 $src
|
||||
echo -n "."
|
||||
}
|
||||
|
||||
# Make sure to pass the test file first and the known good file second
|
||||
diffCheck()
|
||||
{
|
||||
test=$1
|
||||
good=$2
|
||||
|
||||
#run diff and check results
|
||||
diff -q --binary $test $good
|
||||
if [ $? -ne 0 ]; then
|
||||
let ++errors
|
||||
else
|
||||
rm $test
|
||||
fi
|
||||
}
|
||||
|
||||
# **********************************************************************
|
||||
# main
|
||||
|
||||
LD_LIBRARY_PATH=../../src:$LD_LIBRARY_PATH
|
||||
binpath="../../src"
|
||||
datapath="../data"
|
||||
|
||||
test_files="table.jpg smiley2.jpg ext.dat"
|
||||
|
||||
let errors=0
|
||||
cd ./tmp
|
||||
echo
|
||||
|
||||
echo -n "Io tests"
|
||||
for i in $test_files; do ioTest $i; done
|
||||
|
||||
echo -e "\n---------------------------------------------------------"
|
||||
if [ $errors -eq 0 ]; then
|
||||
echo 'All test cases passed'
|
||||
else
|
||||
echo $errors 'test case(s) failed!'
|
||||
fi
|
Loading…
Reference in New Issue