#ifndef __Host_IO_hpp__
#define __Host_IO_hpp__ 1
// =================================================================================================
// Copyright 2010 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the terms
// of the Adobe license agreement accompanying it.
// =================================================================================================
#include "public/include/XMP_Environment.h" // ! This must be the first include.
#include "public/include/XMP_Const.h"
#include "public/include/XMP_IO.hpp"
#include <string>
#if XMP_WinBuild
#include <Windows.h>
#elif XMP_MacBuild
#include <CoreServices/CoreServices.h>
#include <dirent.h> // Mac uses the POSIX folder functions.
#elif XMP_UNIXBuild | XMP_iOSBuild
#include <dirent.h>
#else
#error "Unknown host platform."
#endif
// =================================================================================================
// Host_IO is a collection of minimal convenient wrappers for host I/O services. It is intentionally
// a namespace and not a class. No state is kept here, these are just wrappers that provide a common
// internal API for basic I/O services that differ from host to host.
namespace Host_IO {
// =============================================================================================
// File operations
// ===============
//
// ! The file operations should only be used in the implementation of XMPFiles_IO.
//
// Exists - Returns true if the path exists, whether as a file, folder, or anything else. Never
// throws an exception.
//
// Writable - Returns true
// a. In case checkCreationPossible is false check for existence and writable permissions.
// b. In case checkCreationPossible is true and path is not existence, check permissions of parent folder.
//
// Create - Create a file if possible, return true if successful. Return false if the file
// already exists. Throw an XMP_Error exception if the file cannot be created or if the path
// already exists but is not a file.
//
// GetModifyDate - Return the file system modification date. Returns false if the file or folder
// does not exist.
//
// CreateTemp - Create a (presumably) temporary file related to some other file. The source
// file path is passed in, a derived name is selected in the same folder. The source file need
// not exist, but all folders in the path must exist. The derived name is guaranteed to not
// already exist. A limited number of attempts are made to select a derived name. Returns the
// temporary file path if successful. Throws an XMP_Error exception if no derived name is found
// of if the temporary file cannot be created.
//
// Open - Open a file for read-only or read-write access. Returns the host-specific FileRef if
// successful, returns noFileRef if the path does not exist. Throws an XMP_Error exception for
// other errors.
//
// Close - Close a file. Does nothing if the FileRef is noFileRef. Throws an XMP_Error
// exception for any errors.
//
// SwapData - Swap the contents of two files. Both should be closed. Used as part of safe-save
// operations. On Mac, also swaps all non-data forks. Ideally just the contents should be
// swapped, but a 3-way rename will be used instead of reading and writing the contents. Uses a
// host file-swap service if available, even if that swaps more than the contents. Throws an
// XMP_Error exception for any errors.
//
// Rename - Rename a file or folder. The new path must not exist. Throws an XMP_Error exception
// for any errors.
//
// Delete - Deletes a file or folder. Does nothing if the path does not exist. Throws an
// XMP_Error exception for any errors.
//
// Seek - Change the I/O position of an open file, returning the new absolute offset. Uses the
// native host behavior for seeking beyond EOF. Throws an XMP_Error exception for any errors.
//
// Read - Read into a buffer returning the number of bytes read. Requests are limited to less
// than 2GB in case the host uses an SInt32 count. Throws an XMP_Error exception for errors.
// Reaching EOF or being at EOF is not an error.
//
// Write - Write from a buffer. Requests are limited to less than 2GB in case the host uses an
// SInt32 count. Throws an XMP_Error exception for any errors.
//
// Length - Returns the length of an open file in bytes. The I/O position is not changed.
// Throws an XMP_Error exception for any errors.
//
// SetEOF - Sets a new EOF offset. The I/O position may be changed. Throws an XMP_Error
// exception for any errors.
#if XMP_WinBuild
typedef HANDLE FileRef;
static const FileRef noFileRef = INVALID_HANDLE_VALUE;
#elif XMP_MacBuild
typedef FSIORefNum FileRef;
static const FileRef noFileRef = -1;
#elif XMP_UNIXBuild | XMP_iOSBuild
typedef int FileRef;
static const FileRef noFileRef = -1;
#endif
bool Exists ( const char* filePath );
bool Writable ( const char* path, bool checkCreationPossible = false);
bool Create ( const char* filePath ); // Returns true if file exists or was created.
std::string GetCasePreservedName(const std::string& inputPath);
bool GetModifyDate ( const char* filePath, XMP_DateTime* modifyDate );
std::string CreateTemp ( const char* sourcePath );
enum { openReadOnly = true, openReadWrite = false };
FileRef Open ( const char* filePath, bool readOnly );
void Close ( FileRef file );
void SwapData ( const char* sourcePath, const char* destPath );
void Rename ( const char* oldPath, const char* newPath );
void Delete ( const char* filePath );
XMP_Int64 Seek ( FileRef file, XMP_Int64 offset, SeekMode mode );
XMP_Uns32 Read ( FileRef file, void* buffer, XMP_Uns32 count );
void Write ( FileRef file, const void* buffer, XMP_Uns32 count );
XMP_Int64 Length ( FileRef file );
void SetEOF ( FileRef file, XMP_Int64 length );
inline XMP_Int64 Offset ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromCurrent ); };
inline XMP_Int64 Rewind ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromStart ); }; // Always returns 0.
inline XMP_Int64 ToEOF ( FileRef file ) { return Host_IO::Seek ( file, 0, kXMP_SeekFromEnd ); };
// =============================================================================================
// Folder operations
// =================
//
// ! The folder operations may be used anywhere.
//
// GetFileMode - Returns an enum telling if a path names a file, folder, other, or nothing.
// Never throws an exception.
//
// GetChildMode - Same as GetFileMode, but has separate parent path and child name parameters.
//
// OpenFolder - Initializes the iteration of a folder.
//
// CloseFolder - Terminates the iteration of a folder.
//
// GetNextChild - Steps an iteration of a folder. Returns false at the end. Otherwise returns
// true and the local name of the next child. All names starting with '.' are skipped.
//
// AutoFolder - A utility class to make sure a folder iteration is terminated at scope exit.
enum { kFMode_DoesNotExist, kFMode_IsFile, kFMode_IsFolder, kFMode_IsOther };
typedef XMP_Uns8 FileMode;
FileMode GetFileMode ( const char * path );
FileMode GetChildMode ( const char * parentPath, const char * childName );
#if XMP_WinBuild
typedef HANDLE FolderRef;
static const FolderRef noFolderRef = INVALID_HANDLE_VALUE;
#elif XMP_MacBuild
typedef DIR* FolderRef;
static const FolderRef noFolderRef = 0;
#elif XMP_UNIXBuild | XMP_iOSBuild
typedef DIR* FolderRef;
static const FolderRef noFolderRef = 0;
#endif
FolderRef OpenFolder ( const char* folderPath );
void CloseFolder ( FolderRef folder );
bool GetNextChild ( FolderRef folder, std::string* childName );
class AutoFolder { // Used to make sure folder is closed at scope exit.
public:
FolderRef folder;
AutoFolder() : folder(noFolderRef) {};
~AutoFolder() { this->Close(); };
void Close() { CloseFolder ( this->folder ); this->folder = noFolderRef; };
};
};
#endif // __Host_IO_hpp__