libdcp
file.cc
1 /*
2  Copyright (C) 2022 Carl Hetherington <cth@carlh.net>
3 
4  This file is part of libdcp.
5 
6  libdcp is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  libdcp is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with libdcp. If not, see <http://www.gnu.org/licenses/>.
18 
19  In addition, as a special exception, the copyright holders give
20  permission to link the code of portions of this program with the
21  OpenSSL library under certain conditions as described in each
22  individual source file, and distribute linked combinations
23  including the two.
24 
25  You must obey the GNU General Public License in all respects
26  for all of the code used other than OpenSSL. If you modify
27  file(s) with this exception, you may extend this exception to your
28  version of the file(s), but you are not obligated to do so. If you
29  do not wish to do so, delete this exception statement from your
30  version. If you delete this exception statement from all source
31  files in the program, then also delete it here.
32 */
33 
34 
35 #include "dcp_assert.h"
36 #include "file.h"
37 #include "filesystem.h"
38 #ifdef LIBDCP_WINDOWS
39 #include <errhandlingapi.h>
40 #endif
41 #include <stdio.h>
42 
43 
44 using namespace dcp;
45 
46 
47 File::~File()
48 {
49  close();
50 }
51 
52 
53 File::File(boost::filesystem::path path, std::string mode)
54  : _path(path)
55 {
56 #ifdef LIBDCP_WINDOWS
57  SetLastError(0);
58  std::wstring mode_wide(mode.begin(), mode.end());
59  /* c_str() here should give a UTF-16 string */
60  _file = _wfopen(dcp::filesystem::fix_long_path(path).c_str(), mode_wide.c_str());
61  if (!_file) {
62  _open_error = GetLastError();
63  }
64 #else
65  _file = fopen(path.c_str(), mode.c_str());
66  if (!_file) {
67  _open_error = errno;
68  }
69 #endif
70 }
71 
72 
73 File::File(File&& other)
74  : _path(other._path)
75  , _file(other._file)
76  , _open_error(other._open_error)
77 {
78  other._file = nullptr;
79 }
80 
81 
82 File&
83 File::operator=(File&& other)
84 {
85  if (*this != other) {
86  close();
87  _file = other._file;
88  _open_error = other._open_error;
89  other._file = nullptr;
90  }
91  return *this;
92 }
93 
94 
95 void
97 {
98  if (_file) {
99  fclose(_file);
100  _file = nullptr;
101  }
102 }
103 
104 
105 size_t
106 File::write(const void *ptr, size_t size, size_t nmemb)
107 {
108  DCP_ASSERT(_file);
109  return fwrite(ptr, size, nmemb, _file);
110 }
111 
112 
113 size_t
114 File::read(void *ptr, size_t size, size_t nmemb)
115 {
116  DCP_ASSERT(_file);
117  return fread(ptr, size, nmemb, _file);
118 }
119 
120 
121 int
123 {
124  DCP_ASSERT(_file);
125  return feof(_file);
126 }
127 
128 
129 char *
130 File::gets(char* s, int size)
131 {
132  DCP_ASSERT(_file);
133  return fgets(s, size, _file);
134 }
135 
136 
137 int
138 File::puts(char const* s)
139 {
140  DCP_ASSERT(_file);
141  return fputs(s, _file);
142 }
143 
144 
145 File::operator bool() const
146 {
147  return _file != nullptr;
148 }
149 
150 
151 void
152 File::checked_write(void const * ptr, size_t size)
153 {
154  size_t N = write(ptr, 1, size);
155  if (N != size) {
156  if (ferror(_file)) {
157  throw FileError("fwrite error", _path, errno);
158  } else {
159  throw FileError("Unexpected short write", _path, 0);
160  }
161  }
162 }
163 
164 
165 void
166 File::checked_read(void* ptr, size_t size)
167 {
168  size_t N = read(ptr, 1, size);
169  if (N != size) {
170  if (ferror(_file)) {
171  throw FileError("fread error %1", _path, errno);
172  } else {
173  throw FileError("Unexpected short read", _path, 0);
174  }
175  }
176 }
177 
178 
179 FILE*
181 {
182  auto give = _file;
183  _file = nullptr;
184  return give;
185 }
186 
187 
188 int
189 File::seek(int64_t offset, int whence)
190 {
191  DCP_ASSERT(_file);
192 #ifdef LIBDCP_WINDOWS
193  return _fseeki64(_file, offset, whence);
194 #else
195  return fseek(_file, offset, whence);
196 #endif
197 }
198 
199 
200 int64_t
202 {
203  DCP_ASSERT(_file);
204 #ifdef LIBDCP_WINDOWS
205  return _ftelli64(_file);
206 #else
207  return ftell(_file);
208 #endif
209 }
210 
211 
212 
213 int
215 {
216  DCP_ASSERT(_file);
217  return ferror(_file);
218 }
An exception related to a file.
Definition: exceptions.h:56
Definition: file.h:49
int eof()
Definition: file.cc:122
int64_t tell()
Definition: file.cc:201
File(boost::filesystem::path, std::string mode)
Definition: file.cc:53
char * gets(char *s, int size)
Definition: file.cc:130
void close()
Definition: file.cc:96
int puts(char const *s)
Definition: file.cc:138
FILE * take()
Definition: file.cc:180
size_t write(const void *ptr, size_t size, size_t nmemb)
Definition: file.cc:106
size_t read(void *ptr, size_t size, size_t nmemb)
Definition: file.cc:114
int error()
Definition: file.cc:214
int seek(int64_t offset, int whence)
Definition: file.cc:189
DCP_ASSERT macro.
Namespace for everything in libdcp.
Definition: array_data.h:50