PageRenderTime 27ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/libUPnP/Neptune/Source/System/StdC/NptStdcFile.cpp

https://gitlab.com/sloshedpuppie/LetsGoRetro
C++ | 508 lines | 325 code | 67 blank | 116 comment | 62 complexity | f9ebb743b351d53af065186309995feb MD5 | raw file
  1. /*****************************************************************
  2. |
  3. | Neptune - Files :: Standard C Implementation
  4. |
  5. | (c) 2001-2008 Gilles Boccon-Gibod
  6. | Author: Gilles Boccon-Gibod (bok@bok.net)
  7. |
  8. ****************************************************************/
  9. /*----------------------------------------------------------------------
  10. | includes
  11. +---------------------------------------------------------------------*/
  12. #define _LARGEFILE_SOURCE
  13. #define _LARGEFILE_SOURCE64
  14. #define _FILE_OFFSET_BITS 64
  15. #include <stdio.h>
  16. #if !defined(_WIN32_WCE)
  17. #include <string.h>
  18. #include <sys/stat.h>
  19. #include <errno.h>
  20. #else
  21. #include <stdio.h>
  22. #define errno GetLastError()
  23. #endif
  24. #include "NptConfig.h"
  25. #include "NptUtils.h"
  26. #include "NptFile.h"
  27. #include "NptThreads.h"
  28. #include "NptInterfaces.h"
  29. #include "NptStrings.h"
  30. #include "NptDebug.h"
  31. #if defined(NPT_CONFIG_HAVE_SHARE_H)
  32. #include <share.h>
  33. #endif
  34. #if defined(_WIN32)
  35. extern FILE *NPT_fsopen_utf8(const char* path, const char* mode, int sh_flags);
  36. extern FILE *NPT_fopen_utf8(const char* path, const char* mode);
  37. #define fopen NPT_fopen_utf8
  38. #define fopen_s NPT_fopen_s_utf8
  39. #define _fsopen NPT_fsopen_utf8
  40. #endif
  41. /*----------------------------------------------------------------------
  42. | compatibility wrappers
  43. +---------------------------------------------------------------------*/
  44. #if !defined(NPT_CONFIG_HAVE_FOPEN_S)
  45. static int fopen_s(FILE** file,
  46. const char* filename,
  47. const char* mode)
  48. {
  49. *file = fopen(filename, mode);
  50. #if defined(_WIN32_WCE)
  51. if (*file == NULL) return ENOENT;
  52. #else
  53. if (*file == NULL) return errno;
  54. #endif
  55. return 0;
  56. }
  57. #endif // defined(NPT_CONFIG_HAVE_FOPEN_S
  58. /*----------------------------------------------------------------------
  59. | MapErrno
  60. +---------------------------------------------------------------------*/
  61. static NPT_Result
  62. MapErrno(int err) {
  63. switch (err) {
  64. case EACCES: return NPT_ERROR_PERMISSION_DENIED;
  65. case EPERM: return NPT_ERROR_PERMISSION_DENIED;
  66. case ENOENT: return NPT_ERROR_NO_SUCH_FILE;
  67. #if defined(ENAMETOOLONG)
  68. case ENAMETOOLONG: return NPT_ERROR_INVALID_PARAMETERS;
  69. #endif
  70. case EBUSY: return NPT_ERROR_FILE_BUSY;
  71. case EROFS: return NPT_ERROR_FILE_NOT_WRITABLE;
  72. case ENOTDIR: return NPT_ERROR_FILE_NOT_DIRECTORY;
  73. default: return NPT_ERROR_ERRNO(err);
  74. }
  75. }
  76. /*----------------------------------------------------------------------
  77. | NPT_StdcFileWrapper
  78. +---------------------------------------------------------------------*/
  79. class NPT_StdcFileWrapper
  80. {
  81. public:
  82. // constructors and destructor
  83. NPT_StdcFileWrapper(FILE* file, const char* name) : m_File(file), m_Name(name) {}
  84. ~NPT_StdcFileWrapper() {
  85. if (m_File != NULL &&
  86. m_File != stdin &&
  87. m_File != stdout &&
  88. m_File != stderr) {
  89. fclose(m_File);
  90. }
  91. }
  92. // members
  93. FILE* m_File;
  94. NPT_String m_Name;
  95. };
  96. typedef NPT_Reference<NPT_StdcFileWrapper> NPT_StdcFileReference;
  97. /*----------------------------------------------------------------------
  98. | NPT_StdcFileStream
  99. +---------------------------------------------------------------------*/
  100. class NPT_StdcFileStream
  101. {
  102. public:
  103. // constructors and destructor
  104. NPT_StdcFileStream(NPT_StdcFileReference file) :
  105. m_FileReference(file) {}
  106. // NPT_FileInterface methods
  107. NPT_Result Seek(NPT_Position offset);
  108. NPT_Result Tell(NPT_Position& offset);
  109. NPT_Result Flush();
  110. protected:
  111. // constructors and destructors
  112. virtual ~NPT_StdcFileStream() {}
  113. // members
  114. NPT_StdcFileReference m_FileReference;
  115. };
  116. /*----------------------------------------------------------------------
  117. | NPT_StdcFileStream::Seek
  118. +---------------------------------------------------------------------*/
  119. NPT_Result
  120. NPT_StdcFileStream::Seek(NPT_Position offset)
  121. {
  122. size_t result;
  123. result = NPT_fseek(m_FileReference->m_File, offset, SEEK_SET);
  124. if (result == 0) {
  125. return NPT_SUCCESS;
  126. } else {
  127. return NPT_FAILURE;
  128. }
  129. }
  130. /*----------------------------------------------------------------------
  131. | NPT_StdcFileStream::Tell
  132. +---------------------------------------------------------------------*/
  133. NPT_Result
  134. NPT_StdcFileStream::Tell(NPT_Position& offset)
  135. {
  136. offset = 0;
  137. NPT_Int64 pos = NPT_ftell(m_FileReference->m_File);
  138. if (pos < 0) return NPT_FAILURE;
  139. offset = pos;
  140. return NPT_SUCCESS;
  141. }
  142. /*----------------------------------------------------------------------
  143. | NPT_StdcFileStream::Flush
  144. +---------------------------------------------------------------------*/
  145. NPT_Result
  146. NPT_StdcFileStream::Flush()
  147. {
  148. fflush(m_FileReference->m_File);
  149. return NPT_SUCCESS;
  150. }
  151. /*----------------------------------------------------------------------
  152. | NPT_StdcFileInputStream
  153. +---------------------------------------------------------------------*/
  154. class NPT_StdcFileInputStream : public NPT_InputStream,
  155. private NPT_StdcFileStream
  156. {
  157. public:
  158. // constructors and destructor
  159. NPT_StdcFileInputStream(NPT_StdcFileReference& file) :
  160. NPT_StdcFileStream(file) {}
  161. // NPT_InputStream methods
  162. NPT_Result Read(void* buffer,
  163. NPT_Size bytes_to_read,
  164. NPT_Size* bytes_read);
  165. NPT_Result Seek(NPT_Position offset) {
  166. return NPT_StdcFileStream::Seek(offset);
  167. }
  168. NPT_Result Tell(NPT_Position& offset) {
  169. return NPT_StdcFileStream::Tell(offset);
  170. }
  171. NPT_Result GetSize(NPT_LargeSize& size);
  172. NPT_Result GetAvailable(NPT_LargeSize& available);
  173. };
  174. /*----------------------------------------------------------------------
  175. | NPT_StdcFileInputStream::Read
  176. +---------------------------------------------------------------------*/
  177. NPT_Result
  178. NPT_StdcFileInputStream::Read(void* buffer,
  179. NPT_Size bytes_to_read,
  180. NPT_Size* bytes_read)
  181. {
  182. size_t nb_read;
  183. // check the parameters
  184. if (buffer == NULL) {
  185. return NPT_ERROR_INVALID_PARAMETERS;
  186. }
  187. // read from the file
  188. nb_read = fread(buffer, 1, bytes_to_read, m_FileReference->m_File);
  189. if (nb_read > 0) {
  190. if (bytes_read) *bytes_read = (NPT_Size)nb_read;
  191. return NPT_SUCCESS;
  192. } else if (feof(m_FileReference->m_File)) {
  193. if (bytes_read) *bytes_read = 0;
  194. return NPT_ERROR_EOS;
  195. } else {
  196. if (bytes_read) *bytes_read = 0;
  197. return MapErrno(errno);
  198. }
  199. }
  200. /*----------------------------------------------------------------------
  201. | NPT_StdcFileInputStream::GetSize
  202. +---------------------------------------------------------------------*/
  203. NPT_Result
  204. NPT_StdcFileInputStream::GetSize(NPT_LargeSize& size)
  205. {
  206. NPT_FileInfo file_info;
  207. NPT_Result result = NPT_File::GetInfo(m_FileReference->m_Name, &file_info);
  208. if (NPT_FAILED(result)) return result;
  209. size = file_info.m_Size;
  210. return NPT_SUCCESS;
  211. }
  212. /*----------------------------------------------------------------------
  213. | NPT_StdcFileInputStream::GetAvailable
  214. +---------------------------------------------------------------------*/
  215. NPT_Result
  216. NPT_StdcFileInputStream::GetAvailable(NPT_LargeSize& available)
  217. {
  218. NPT_Int64 offset = NPT_ftell(m_FileReference->m_File);
  219. NPT_LargeSize size = 0;
  220. if (NPT_SUCCEEDED(GetSize(size)) && offset >= 0 && (NPT_LargeSize)offset <= size) {
  221. available = size - offset;
  222. return NPT_SUCCESS;
  223. } else {
  224. available = 0;
  225. return NPT_FAILURE;
  226. }
  227. }
  228. /*----------------------------------------------------------------------
  229. | NPT_StdcFileOutputStream
  230. +---------------------------------------------------------------------*/
  231. class NPT_StdcFileOutputStream : public NPT_OutputStream,
  232. private NPT_StdcFileStream
  233. {
  234. public:
  235. // constructors and destructor
  236. NPT_StdcFileOutputStream(NPT_StdcFileReference& file) :
  237. NPT_StdcFileStream(file) {}
  238. // NPT_InputStream methods
  239. NPT_Result Write(const void* buffer,
  240. NPT_Size bytes_to_write,
  241. NPT_Size* bytes_written);
  242. NPT_Result Seek(NPT_Position offset) {
  243. return NPT_StdcFileStream::Seek(offset);
  244. }
  245. NPT_Result Tell(NPT_Position& offset) {
  246. return NPT_StdcFileStream::Tell(offset);
  247. }
  248. NPT_Result Flush() {
  249. return NPT_StdcFileStream::Flush();
  250. }
  251. };
  252. /*----------------------------------------------------------------------
  253. | NPT_StdcFileOutputStream::Write
  254. +---------------------------------------------------------------------*/
  255. NPT_Result
  256. NPT_StdcFileOutputStream::Write(const void* buffer,
  257. NPT_Size bytes_to_write,
  258. NPT_Size* bytes_written)
  259. {
  260. size_t nb_written;
  261. nb_written = fwrite(buffer, 1, bytes_to_write, m_FileReference->m_File);
  262. if (nb_written > 0) {
  263. if (bytes_written) *bytes_written = (NPT_Size)nb_written;
  264. return NPT_SUCCESS;
  265. } else {
  266. if (bytes_written) *bytes_written = 0;
  267. return NPT_ERROR_WRITE_FAILED;
  268. }
  269. }
  270. /*----------------------------------------------------------------------
  271. | NPT_StdcFile
  272. +---------------------------------------------------------------------*/
  273. class NPT_StdcFile: public NPT_FileInterface
  274. {
  275. public:
  276. // constructors and destructor
  277. NPT_StdcFile(NPT_File& delegator);
  278. ~NPT_StdcFile();
  279. // NPT_FileInterface methods
  280. NPT_Result Open(OpenMode mode);
  281. NPT_Result Close();
  282. NPT_Result GetInputStream(NPT_InputStreamReference& stream);
  283. NPT_Result GetOutputStream(NPT_OutputStreamReference& stream);
  284. private:
  285. // members
  286. NPT_File& m_Delegator;
  287. OpenMode m_Mode;
  288. NPT_StdcFileReference m_FileReference;
  289. };
  290. /*----------------------------------------------------------------------
  291. | NPT_StdcFile::NPT_StdcFile
  292. +---------------------------------------------------------------------*/
  293. NPT_StdcFile::NPT_StdcFile(NPT_File& delegator) :
  294. m_Delegator(delegator),
  295. m_Mode(0)
  296. {
  297. }
  298. /*----------------------------------------------------------------------
  299. | NPT_StdcFile::~NPT_StdcFile
  300. +---------------------------------------------------------------------*/
  301. NPT_StdcFile::~NPT_StdcFile()
  302. {
  303. Close();
  304. }
  305. /*----------------------------------------------------------------------
  306. | NPT_StdcFile::Open
  307. +---------------------------------------------------------------------*/
  308. NPT_Result
  309. NPT_StdcFile::Open(NPT_File::OpenMode mode)
  310. {
  311. FILE* file = NULL;
  312. // check if we're already open
  313. if (!m_FileReference.IsNull()) {
  314. return NPT_ERROR_FILE_ALREADY_OPEN;
  315. }
  316. // store the mode
  317. m_Mode = mode;
  318. // check for special names
  319. const char* name = (const char*)m_Delegator.GetPath();
  320. if (NPT_StringsEqual(name, NPT_FILE_STANDARD_INPUT)) {
  321. file = stdin;
  322. } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_OUTPUT)) {
  323. file = stdout;
  324. } else if (NPT_StringsEqual(name, NPT_FILE_STANDARD_ERROR)) {
  325. file = stderr;
  326. } else {
  327. // compute mode
  328. const char* fmode = "";
  329. if (mode & NPT_FILE_OPEN_MODE_WRITE) {
  330. if (mode & NPT_FILE_OPEN_MODE_APPEND) {
  331. /* write, read, create, append */
  332. /* (append implies create) */
  333. fmode = "a+b";
  334. } else {
  335. if ((mode & NPT_FILE_OPEN_MODE_CREATE) || (mode & NPT_FILE_OPEN_MODE_TRUNCATE)) {
  336. /* write, read, create, truncate */
  337. /* (truncate implies create, create implies truncate) */
  338. fmode = "w+b";
  339. } else {
  340. /* write, read */
  341. fmode = "r+b";
  342. }
  343. }
  344. } else {
  345. /* read only */
  346. fmode = "rb";
  347. }
  348. // open the file
  349. #if defined(NPT_CONFIG_HAVE_FSOPEN)
  350. file = _fsopen(name, fmode, _SH_DENYNO);
  351. int open_result = file == NULL ? ENOENT : 0;
  352. #else
  353. int open_result = fopen_s(&file, name, fmode);
  354. #endif
  355. // test the result of the open
  356. if (open_result != 0) return MapErrno(open_result);
  357. }
  358. // unbuffer the file if needed
  359. if ((mode & NPT_FILE_OPEN_MODE_UNBUFFERED) && file != NULL) {
  360. #if !defined(_WIN32_WCE)
  361. setvbuf(file, NULL, _IONBF, 0);
  362. #endif
  363. }
  364. // create a reference to the FILE object
  365. m_FileReference = new NPT_StdcFileWrapper(file, name);
  366. return NPT_SUCCESS;
  367. }
  368. /*----------------------------------------------------------------------
  369. | NPT_StdcFile::Close
  370. +---------------------------------------------------------------------*/
  371. NPT_Result
  372. NPT_StdcFile::Close()
  373. {
  374. // release the file reference
  375. m_FileReference = NULL;
  376. // reset the mode
  377. m_Mode = 0;
  378. return NPT_SUCCESS;
  379. }
  380. /*----------------------------------------------------------------------
  381. | NPT_StdcFile::GetInputStream
  382. +---------------------------------------------------------------------*/
  383. NPT_Result
  384. NPT_StdcFile::GetInputStream(NPT_InputStreamReference& stream)
  385. {
  386. // default value
  387. stream = NULL;
  388. // check that the file is open
  389. if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN;
  390. // check that the mode is compatible
  391. if (!(m_Mode & NPT_FILE_OPEN_MODE_READ)) {
  392. return NPT_ERROR_FILE_NOT_READABLE;
  393. }
  394. // create a stream
  395. stream = new NPT_StdcFileInputStream(m_FileReference);
  396. return NPT_SUCCESS;
  397. }
  398. /*----------------------------------------------------------------------
  399. | NPT_StdcFile::GetOutputStream
  400. +---------------------------------------------------------------------*/
  401. NPT_Result
  402. NPT_StdcFile::GetOutputStream(NPT_OutputStreamReference& stream)
  403. {
  404. // default value
  405. stream = NULL;
  406. // check that the file is open
  407. if (m_FileReference.IsNull()) return NPT_ERROR_FILE_NOT_OPEN;
  408. // check that the mode is compatible
  409. if (!(m_Mode & NPT_FILE_OPEN_MODE_WRITE)) {
  410. return NPT_ERROR_FILE_NOT_WRITABLE;
  411. }
  412. // create a stream
  413. stream = new NPT_StdcFileOutputStream(m_FileReference);
  414. return NPT_SUCCESS;
  415. }
  416. /*----------------------------------------------------------------------
  417. | NPT_File::NPT_File
  418. +---------------------------------------------------------------------*/
  419. NPT_File::NPT_File(const char* path) : m_Path(path), m_IsSpecial(false)
  420. {
  421. m_Delegate = new NPT_StdcFile(*this);
  422. if (NPT_StringsEqual(path, NPT_FILE_STANDARD_INPUT) ||
  423. NPT_StringsEqual(path, NPT_FILE_STANDARD_OUTPUT) ||
  424. NPT_StringsEqual(path, NPT_FILE_STANDARD_ERROR)) {
  425. m_IsSpecial = true;
  426. }
  427. }
  428. /*----------------------------------------------------------------------
  429. | NPT_File::operator=
  430. +---------------------------------------------------------------------*/
  431. NPT_File&
  432. NPT_File::operator=(const NPT_File& file)
  433. {
  434. if (this != &file) {
  435. delete m_Delegate;
  436. m_Path = file.m_Path;
  437. m_IsSpecial = file.m_IsSpecial;
  438. m_Delegate = new NPT_StdcFile(*this);
  439. }
  440. return *this;
  441. }