stdstream.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. // This code is in the public domain -- Ignacio Castaño <[email protected]>
  2. #include "nvcore.h"
  3. #include "stream.h"
  4. #include "array.h"
  5. #include <stdio.h> // fopen
  6. #include <string.h> // memcpy
  7. namespace nv
  8. {
  9. // Portable version of fopen.
  10. inline FILE * fileOpen(const char * fileName, const char * mode)
  11. {
  12. nvCheck(fileName != NULL);
  13. #if NV_CC_MSVC && _MSC_VER >= 1400
  14. FILE * fp;
  15. if (fopen_s(&fp, fileName, mode) == 0) {
  16. return fp;
  17. }
  18. return NULL;
  19. #else
  20. return fopen(fileName, mode);
  21. #endif
  22. }
  23. /// Base stdio stream.
  24. class NVCORE_CLASS StdStream : public Stream
  25. {
  26. NV_FORBID_COPY(StdStream);
  27. public:
  28. /// Ctor.
  29. StdStream( FILE * fp, bool autoclose ) : m_fp(fp), m_autoclose(autoclose) { }
  30. /// Dtor.
  31. virtual ~StdStream()
  32. {
  33. if( m_fp != NULL && m_autoclose ) {
  34. #if NV_OS_WIN32
  35. _fclose_nolock( m_fp );
  36. #else
  37. fclose( m_fp );
  38. #endif
  39. }
  40. }
  41. /** @name Stream implementation. */
  42. //@{
  43. virtual void seek( uint pos )
  44. {
  45. nvDebugCheck(m_fp != NULL);
  46. nvDebugCheck(pos <= size());
  47. #if NV_OS_WIN32
  48. _fseek_nolock(m_fp, pos, SEEK_SET);
  49. #else
  50. fseek(m_fp, pos, SEEK_SET);
  51. #endif
  52. }
  53. virtual uint tell() const
  54. {
  55. nvDebugCheck(m_fp != NULL);
  56. #if NV_OS_WIN32
  57. return _ftell_nolock(m_fp);
  58. #else
  59. return (uint)ftell(m_fp);
  60. #endif
  61. }
  62. virtual uint size() const
  63. {
  64. nvDebugCheck(m_fp != NULL);
  65. #if NV_OS_WIN32
  66. uint pos = _ftell_nolock(m_fp);
  67. _fseek_nolock(m_fp, 0, SEEK_END);
  68. uint end = _ftell_nolock(m_fp);
  69. _fseek_nolock(m_fp, pos, SEEK_SET);
  70. #else
  71. uint pos = (uint)ftell(m_fp);
  72. fseek(m_fp, 0, SEEK_END);
  73. uint end = (uint)ftell(m_fp);
  74. fseek(m_fp, pos, SEEK_SET);
  75. #endif
  76. return end;
  77. }
  78. virtual bool isError() const
  79. {
  80. return m_fp == NULL || ferror( m_fp ) != 0;
  81. }
  82. virtual void clearError()
  83. {
  84. nvDebugCheck(m_fp != NULL);
  85. clearerr(m_fp);
  86. }
  87. // @@ The original implementation uses feof, which only returns true when we attempt to read *past* the end of the stream.
  88. // That is, if we read the last byte of a file, then isAtEnd would still return false, even though the stream pointer is at the file end. This is not the intent and was inconsistent with the implementation of the MemoryStream, a better
  89. // implementation uses use ftell and fseek to determine our location within the file.
  90. virtual bool isAtEnd() const
  91. {
  92. if (m_fp == NULL) return true;
  93. //nvDebugCheck(m_fp != NULL);
  94. //return feof( m_fp ) != 0;
  95. #if NV_OS_WIN32
  96. uint pos = _ftell_nolock(m_fp);
  97. _fseek_nolock(m_fp, 0, SEEK_END);
  98. uint end = _ftell_nolock(m_fp);
  99. _fseek_nolock(m_fp, pos, SEEK_SET);
  100. #else
  101. uint pos = (uint)ftell(m_fp);
  102. fseek(m_fp, 0, SEEK_END);
  103. uint end = (uint)ftell(m_fp);
  104. fseek(m_fp, pos, SEEK_SET);
  105. #endif
  106. return pos == end;
  107. }
  108. /// Always true.
  109. virtual bool isSeekable() const { return true; }
  110. //@}
  111. protected:
  112. FILE * m_fp;
  113. bool m_autoclose;
  114. };
  115. /// Standard output stream.
  116. class NVCORE_CLASS StdOutputStream : public StdStream
  117. {
  118. NV_FORBID_COPY(StdOutputStream);
  119. public:
  120. /// Construct stream by file name.
  121. StdOutputStream( const char * name ) : StdStream(fileOpen(name, "wb"), /*autoclose=*/true) { }
  122. /// Construct stream by file handle.
  123. StdOutputStream( FILE * fp, bool autoclose ) : StdStream(fp, autoclose)
  124. {
  125. }
  126. /** @name Stream implementation. */
  127. //@{
  128. /// Write data.
  129. virtual uint serialize( void * data, uint len )
  130. {
  131. nvDebugCheck(data != NULL);
  132. nvDebugCheck(m_fp != NULL);
  133. #if NV_OS_WIN32
  134. return (uint)_fwrite_nolock(data, 1, len, m_fp);
  135. #elif NV_OS_LINUX
  136. return (uint)fwrite_unlocked(data, 1, len, m_fp);
  137. #elif NV_OS_DARWIN
  138. // @@ No error checking, always returns len.
  139. for (uint i = 0; i < len; i++) {
  140. putc_unlocked(((char *)data)[i], m_fp);
  141. }
  142. return len;
  143. #else
  144. return (uint)fwrite(data, 1, len, m_fp);
  145. #endif
  146. }
  147. virtual bool isLoading() const
  148. {
  149. return false;
  150. }
  151. virtual bool isSaving() const
  152. {
  153. return true;
  154. }
  155. //@}
  156. };
  157. /// Standard input stream.
  158. class NVCORE_CLASS StdInputStream : public StdStream
  159. {
  160. NV_FORBID_COPY(StdInputStream);
  161. public:
  162. /// Construct stream by file name.
  163. StdInputStream( const char * name ) : StdStream(fileOpen(name, "rb"), /*autoclose=*/true) { }
  164. /// Construct stream by file handle.
  165. StdInputStream( FILE * fp, bool autoclose=true ) : StdStream(fp, autoclose)
  166. {
  167. }
  168. /** @name Stream implementation. */
  169. //@{
  170. /// Read data.
  171. virtual uint serialize( void * data, uint len )
  172. {
  173. nvDebugCheck(data != NULL);
  174. nvDebugCheck(m_fp != NULL);
  175. #if NV_OS_WIN32
  176. return (uint)_fread_nolock(data, 1, len, m_fp);
  177. #elif NV_OS_LINUX
  178. return (uint)fread_unlocked(data, 1, len, m_fp);
  179. #elif NV_OS_DARWIN
  180. // @@ No error checking, always returns len.
  181. for (uint i = 0; i < len; i++) {
  182. ((char *)data)[i] = getc_unlocked(m_fp);
  183. }
  184. return len;
  185. #else
  186. return (uint)fread(data, 1, len, m_fp);
  187. #endif
  188. }
  189. virtual bool isLoading() const
  190. {
  191. return true;
  192. }
  193. virtual bool isSaving() const
  194. {
  195. return false;
  196. }
  197. //@}
  198. };
  199. /// Memory input stream.
  200. class NVCORE_CLASS MemoryInputStream : public Stream
  201. {
  202. NV_FORBID_COPY(MemoryInputStream);
  203. public:
  204. /// Ctor.
  205. MemoryInputStream( const uint8 * mem, uint size ) : m_mem(mem), m_ptr(mem), m_size(size) { }
  206. /** @name Stream implementation. */
  207. //@{
  208. /// Read data.
  209. virtual uint serialize( void * data, uint len )
  210. {
  211. nvDebugCheck(data != NULL);
  212. nvDebugCheck(!isError());
  213. uint left = m_size - tell();
  214. if (len > left) len = left;
  215. memcpy( data, m_ptr, len );
  216. m_ptr += len;
  217. return len;
  218. }
  219. virtual void seek( uint pos )
  220. {
  221. nvDebugCheck(!isError());
  222. m_ptr = m_mem + pos;
  223. nvDebugCheck(!isError());
  224. }
  225. virtual uint tell() const
  226. {
  227. nvDebugCheck(m_ptr >= m_mem);
  228. return uint(m_ptr - m_mem);
  229. }
  230. virtual uint size() const
  231. {
  232. return m_size;
  233. }
  234. virtual bool isError() const
  235. {
  236. return m_mem == NULL || m_ptr > m_mem + m_size || m_ptr < m_mem;
  237. }
  238. virtual void clearError()
  239. {
  240. // Nothing to do.
  241. }
  242. virtual bool isAtEnd() const
  243. {
  244. return m_ptr == m_mem + m_size;
  245. }
  246. /// Always true.
  247. virtual bool isSeekable() const
  248. {
  249. return true;
  250. }
  251. virtual bool isLoading() const
  252. {
  253. return true;
  254. }
  255. virtual bool isSaving() const
  256. {
  257. return false;
  258. }
  259. //@}
  260. const uint8 * ptr() const { return m_ptr; }
  261. private:
  262. const uint8 * m_mem;
  263. const uint8 * m_ptr;
  264. uint m_size;
  265. };
  266. /// Buffer output stream.
  267. class NVCORE_CLASS BufferOutputStream : public Stream
  268. {
  269. NV_FORBID_COPY(BufferOutputStream);
  270. public:
  271. BufferOutputStream(Array<uint8> & buffer) : m_buffer(buffer) { }
  272. virtual uint serialize( void * data, uint len )
  273. {
  274. nvDebugCheck(data != NULL);
  275. m_buffer.append((uint8 *)data, len);
  276. return len;
  277. }
  278. virtual void seek( uint /*pos*/ ) { /*Not implemented*/ }
  279. virtual uint tell() const { return m_buffer.size(); }
  280. virtual uint size() const { return m_buffer.size(); }
  281. virtual bool isError() const { return false; }
  282. virtual void clearError() {}
  283. virtual bool isAtEnd() const { return true; }
  284. virtual bool isSeekable() const { return false; }
  285. virtual bool isLoading() const { return false; }
  286. virtual bool isSaving() const { return true; }
  287. private:
  288. Array<uint8> & m_buffer;
  289. };
  290. /// Protected input stream.
  291. class NVCORE_CLASS ProtectedStream : public Stream
  292. {
  293. NV_FORBID_COPY(ProtectedStream);
  294. public:
  295. /// Ctor.
  296. ProtectedStream( Stream & s ) : m_s(&s), m_autodelete(false)
  297. {
  298. }
  299. /// Ctor.
  300. ProtectedStream( Stream * s, bool autodelete = true ) :
  301. m_s(s), m_autodelete(autodelete)
  302. {
  303. nvDebugCheck(m_s != NULL);
  304. }
  305. /// Dtor.
  306. virtual ~ProtectedStream()
  307. {
  308. if( m_autodelete ) {
  309. delete m_s;
  310. }
  311. }
  312. /** @name Stream implementation. */
  313. //@{
  314. /// Read data.
  315. virtual uint serialize( void * data, uint len )
  316. {
  317. nvDebugCheck(data != NULL);
  318. len = m_s->serialize( data, len );
  319. if( m_s->isError() ) {
  320. throw;
  321. }
  322. return len;
  323. }
  324. virtual void seek( uint pos )
  325. {
  326. m_s->seek( pos );
  327. if( m_s->isError() ) {
  328. throw;
  329. }
  330. }
  331. virtual uint tell() const
  332. {
  333. return m_s->tell();
  334. }
  335. virtual uint size() const
  336. {
  337. return m_s->size();
  338. }
  339. virtual bool isError() const
  340. {
  341. return m_s->isError();
  342. }
  343. virtual void clearError()
  344. {
  345. m_s->clearError();
  346. }
  347. virtual bool isAtEnd() const
  348. {
  349. return m_s->isAtEnd();
  350. }
  351. virtual bool isSeekable() const
  352. {
  353. return m_s->isSeekable();
  354. }
  355. virtual bool isLoading() const
  356. {
  357. return m_s->isLoading();
  358. }
  359. virtual bool isSaving() const
  360. {
  361. return m_s->isSaving();
  362. }
  363. //@}
  364. private:
  365. Stream * const m_s;
  366. bool const m_autodelete;
  367. };
  368. } // nv namespace
  369. //#endif // NV_CORE_STDSTREAM_H