summaryrefslogtreecommitdiff
path: root/source/Host_IO.hpp
blob: 5bf699287683406a84b6feb6d1d514fff52078fe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
#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
	#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.
	//
	// 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
		typedef int FileRef;
		static const FileRef noFileRef = -1;
	#endif

	bool Exists ( const char* filePath );
	bool Create ( const char* filePath );	// Returns true if file exists or was created.
	
	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
		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__