libcm is a C development framework with an emphasis on audio signal processing applications.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cmFile.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmRpt.h"
  4. #include "cmErr.h"
  5. #include "cmFile.h"
  6. #include "cmMem.h"
  7. #include "cmMallocDebug.h"
  8. #include <sys/stat.h>
  9. cmFileH_t cmFileNullHandle = { NULL };
  10. typedef struct
  11. {
  12. FILE* fp;
  13. cmErr_t err;
  14. cmChar_t* fnStr;
  15. } cmFile_t;
  16. cmFile_t* _cmFileHandleToPtr( cmFileH_t h )
  17. {
  18. cmFile_t* p = (cmFile_t*)h.h;
  19. assert(p != NULL);
  20. return p;
  21. }
  22. cmFileRC_t _cmFileError( cmFile_t* p, cmFileRC_t rc, int errNumb, const cmChar_t* msg )
  23. {
  24. if(errNumb == 0)
  25. rc = cmErrMsg(&p->err,rc,"%s on file '%s'",msg,p->fnStr);
  26. else
  27. rc = cmErrMsg(&p->err,rc,"%s on file '%s'\nSystem Msg:%s",msg,p->fnStr,strerror(errNumb));
  28. return rc;
  29. }
  30. cmFileRC_t cmFileOpen( cmFileH_t* hp, const cmChar_t* fn, enum cmFileOpenFlags_t flags, cmRpt_t* rpt )
  31. {
  32. char mode[] = "/0/0/0";
  33. cmFile_t* p = NULL;
  34. cmErr_t err;
  35. cmFileRC_t rc;
  36. if((rc = cmFileClose(hp)) != kOkFileRC )
  37. return rc;
  38. cmErrSetup(&err,rpt,"File");
  39. hp->h = NULL;
  40. if( cmIsFlag(flags,kReadFileFl) )
  41. mode[0]='r';
  42. else
  43. if( cmIsFlag(flags,kWriteFileFl) )
  44. mode[0]='w';
  45. else
  46. if( cmIsFlag(flags,kAppendFileFl) )
  47. mode[0]='a';
  48. else
  49. cmErrMsg(&err,kInvalidFlagFileRC,"File open flags must contain 'kReadFileFl','kWriteFileFl', or 'kAppendFileFl'.");
  50. if( cmIsFlag(flags,kUpdateFileFl) )
  51. mode[1]='+';
  52. if( fn == NULL )
  53. return cmErrMsg(&err,kObjAllocFailFileRC,"File object allocation failed due to empty file name.");
  54. unsigned byteCnt = sizeof(cmFile_t) + strlen(fn) + 1;
  55. if((p = (cmFile_t*)cmMemMallocZ(byteCnt)) == NULL )
  56. return cmErrMsg(&err,kObjAllocFailFileRC,"File object allocation failed for file '%s'.",cmStringNullGuard(fn));
  57. cmErrClone(&p->err,&err);
  58. p->fnStr = (cmChar_t*)(p+1);
  59. strcpy(p->fnStr,fn);
  60. errno = 0;
  61. if((p->fp = fopen(fn,mode)) == NULL )
  62. {
  63. cmFileRC_t rc = _cmFileError(p,kOpenFailFileRC,errno,"File open failed");
  64. cmMemFree(p);
  65. return rc;
  66. }
  67. hp->h = p;
  68. return kOkFileRC;
  69. }
  70. cmFileRC_t cmFileClose( cmFileH_t* hp )
  71. {
  72. if( cmFileIsValid(*hp) == false )
  73. return kOkFileRC;
  74. cmFile_t* p = _cmFileHandleToPtr(*hp);
  75. errno = 0;
  76. if( p->fp != NULL )
  77. if( fclose(p->fp) != 0 )
  78. return _cmFileError(p,kCloseFailFileRC,errno,"File close failed");
  79. cmMemFree(p);
  80. hp->h = NULL;
  81. return kOkFileRC;
  82. }
  83. bool cmFileIsValid( cmFileH_t h )
  84. { return h.h != NULL; }
  85. cmFileRC_t cmFileRead( cmFileH_t h, void* buf, unsigned bufByteCnt )
  86. {
  87. cmFile_t* p = _cmFileHandleToPtr(h);
  88. errno = 0;
  89. if( fread(buf,bufByteCnt,1,p->fp) != 1 )
  90. return _cmFileError(p,kReadFailFileRC,errno,"File read failed");
  91. return kOkFileRC;
  92. }
  93. cmFileRC_t cmFileWrite( cmFileH_t h, const void* buf, unsigned bufByteCnt )
  94. {
  95. cmFile_t* p = _cmFileHandleToPtr(h);
  96. errno = 0;
  97. if( fwrite(buf,bufByteCnt,1,p->fp) != 1 )
  98. return _cmFileError(p,kWriteFailFileRC,errno,"File write failed");
  99. return kOkFileRC;
  100. }
  101. cmFileRC_t cmFileSeek( cmFileH_t h, enum cmFileSeekFlags_t flags, int offsByteCnt )
  102. {
  103. cmFile_t* p = _cmFileHandleToPtr(h);
  104. unsigned fileflags = 0;
  105. if( cmIsFlag(flags,kBeginFileFl) )
  106. fileflags = SEEK_SET;
  107. else
  108. if( cmIsFlag(flags,kCurFileFl) )
  109. fileflags = SEEK_CUR;
  110. else
  111. if( cmIsFlag(flags,kEndFileFl) )
  112. fileflags = SEEK_END;
  113. else
  114. return cmErrMsg(&p->err,kInvalidFlagFileRC,"Invalid file seek flag on '%s'.",p->fnStr);
  115. errno = 0;
  116. if( fseek(p->fp,offsByteCnt,fileflags) != 0 )
  117. return _cmFileError(p,kSeekFailFileRC,errno,"File seek failed");
  118. return kOkFileRC;
  119. }
  120. cmFileRC_t cmFileTell( cmFileH_t h, long* offsPtr )
  121. {
  122. assert( offsPtr != NULL );
  123. *offsPtr = -1;
  124. cmFile_t* p = _cmFileHandleToPtr(h);
  125. errno = 0;
  126. if((*offsPtr = ftell(p->fp)) == -1)
  127. return _cmFileError(p,kTellFailFileRC,errno,"File tell failed");
  128. return kOkFileRC;
  129. }
  130. bool cmFileEof( cmFileH_t h )
  131. { return feof( _cmFileHandleToPtr(h)->fp ) != 0; }
  132. unsigned cmFileByteCount( cmFileH_t h )
  133. {
  134. struct stat sr;
  135. int f;
  136. cmFile_t* p = _cmFileHandleToPtr(h);
  137. const cmChar_t errMsg[] = "File byte count request failed.";
  138. errno = 0;
  139. if((f = fileno(p->fp)) == -1)
  140. {
  141. _cmFileError(p,kHandleInvalidFileRC,errno,errMsg);
  142. return 0;
  143. }
  144. if(fstat(f,&sr) == -1)
  145. {
  146. _cmFileError(p,kStatFailFileRC,errno,errMsg);
  147. return 0;
  148. }
  149. return sr.st_size;
  150. }
  151. const cmChar_t* cmFileName( cmFileH_t h )
  152. {
  153. cmFile_t* p = _cmFileHandleToPtr(h);
  154. return p->fnStr;
  155. }
  156. cmFileRC_t cmFileFnWrite( const cmChar_t* fn, cmRpt_t* rpt, const void* buf, unsigned bufByteCnt )
  157. {
  158. cmFileH_t h = cmFileNullHandle;
  159. cmFileRC_t rc;
  160. if((rc = cmFileOpen(&h,fn,kWriteFileFl,rpt)) != kOkFileRC )
  161. goto errLabel;
  162. rc = cmFileWrite(h,buf,bufByteCnt);
  163. errLabel:
  164. cmFileClose(&h);
  165. return rc;
  166. }
  167. cmChar_t* _cmFileToBuf( cmFileH_t h, unsigned nn, unsigned* bufByteCntPtr )
  168. {
  169. errno = 0;
  170. unsigned n = cmFileByteCount(h);
  171. cmChar_t* buf = NULL;
  172. cmFile_t* p = _cmFileHandleToPtr(h);
  173. // if the file size calculation is ok
  174. if( errno != 0 )
  175. {
  176. _cmFileError(p,kBufAllocFailFileRC,errno,"Invalid file buffer length.");
  177. goto errLabel;
  178. }
  179. // allocate the read target buffer
  180. if((buf = cmMemAlloc(cmChar_t,n+nn)) == NULL)
  181. {
  182. _cmFileError(p,kBufAllocFailFileRC,0,"Read buffer allocation failed.");
  183. goto errLabel;
  184. }
  185. // read the file
  186. if( cmFileRead(h,buf,n) != kOkFileRC )
  187. goto errLabel;
  188. // zero memory after the file data
  189. memset(buf+n,0,nn);
  190. if( bufByteCntPtr != NULL )
  191. *bufByteCntPtr = n;
  192. return buf;
  193. errLabel:
  194. if( bufByteCntPtr != NULL )
  195. *bufByteCntPtr = 0;
  196. cmMemFree(buf);
  197. return NULL;
  198. }
  199. cmChar_t* _cmFileFnToBuf( const cmChar_t* fn, cmRpt_t* rpt, unsigned nn, unsigned* bufByteCntPtr )
  200. {
  201. cmFileH_t h = cmFileNullHandle;
  202. cmChar_t* buf = NULL;
  203. if( cmFileOpen(&h,fn,kReadFileFl | kBinaryFileFl,rpt) != kOkFileRC )
  204. goto errLabel;
  205. buf = _cmFileToBuf(h,nn,bufByteCntPtr);
  206. errLabel:
  207. cmFileClose(&h);
  208. return buf;
  209. }
  210. cmChar_t* cmFileToBuf( cmFileH_t h, unsigned* bufByteCntPtr )
  211. { return _cmFileToBuf(h,0,bufByteCntPtr); }
  212. cmChar_t* cmFileFnToBuf( const cmChar_t* fn, cmRpt_t* rpt, unsigned* bufByteCntPtr )
  213. { return _cmFileFnToBuf(fn,rpt,0,bufByteCntPtr); }
  214. cmChar_t* cmFileToStr( cmFileH_t h, unsigned* bufByteCntPtr )
  215. { return _cmFileToBuf(h,1,bufByteCntPtr); }
  216. cmChar_t* cmFileFnToStr( const cmChar_t* fn, cmRpt_t* rpt, unsigned* bufByteCntPtr )
  217. { return _cmFileFnToBuf(fn,rpt,1,bufByteCntPtr); }
  218. cmFileRC_t cmFileLineCount( cmFileH_t h, unsigned* lineCntPtr )
  219. {
  220. cmFileRC_t rc = kOkFileRC;
  221. cmFile_t* p = _cmFileHandleToPtr(h);
  222. unsigned lineCnt = 0;
  223. long offs;
  224. int c;
  225. assert( lineCntPtr != NULL );
  226. *lineCntPtr = 0;
  227. if((rc = cmFileTell(h,&offs)) != kOkFileRC )
  228. return rc;
  229. errno = 0;
  230. while(1)
  231. {
  232. c = fgetc(p->fp);
  233. if( c == EOF )
  234. {
  235. if( errno )
  236. rc =_cmFileError(p,kReadFailFileRC,errno,"File read char failed");
  237. else
  238. ++lineCnt; // add one in case the last line isn't terminated with a '\n'.
  239. break;
  240. }
  241. // if an end-of-line was encountered
  242. if( c == '\n' )
  243. ++lineCnt;
  244. }
  245. if((rc = cmFileSeek(h,kBeginFileFl,offs)) != kOkFileRC )
  246. return rc;
  247. *lineCntPtr = lineCnt;
  248. return rc;
  249. }
  250. cmFileRC_t _cmFileGetLine( cmFile_t* p, cmChar_t* buf, unsigned* bufByteCntPtr )
  251. {
  252. // fgets() reads up to n-1 bytes into buf[]
  253. if( fgets(buf,*bufByteCntPtr,p->fp) == NULL )
  254. {
  255. // an read error or EOF condition occurred
  256. *bufByteCntPtr = 0;
  257. if( !feof(p->fp ) )
  258. return _cmFileError(p,kReadFailFileRC,errno,"File read line failed");
  259. return kReadFailFileRC;
  260. }
  261. return kOkFileRC;
  262. }
  263. cmFileRC_t cmFileGetLine( cmFileH_t h, cmChar_t* buf, unsigned* bufByteCntPtr )
  264. {
  265. assert( bufByteCntPtr != NULL );
  266. cmFile_t* p = _cmFileHandleToPtr(h);
  267. unsigned tn = 128;
  268. cmChar_t t[ tn ];
  269. unsigned on = *bufByteCntPtr;
  270. long offs;
  271. cmFileRC_t rc;
  272. // store the current file offset
  273. if((rc = cmFileTell(h,&offs)) != kOkFileRC )
  274. return rc;
  275. // if no buffer was given then use t[]
  276. if( buf == NULL || *bufByteCntPtr == 0 )
  277. {
  278. *bufByteCntPtr = tn;
  279. buf = t;
  280. }
  281. // fill the buffer from the current line
  282. if((rc = _cmFileGetLine(p,buf,bufByteCntPtr)) != kOkFileRC )
  283. return rc;
  284. // get length of the string in the buffer
  285. // (this is one less than the count of bytes written to the buffer)
  286. unsigned n = strlen(buf);
  287. // if the provided buffer was large enough to read the entire string
  288. if( on > n+1 )
  289. {
  290. //*bufByteCntPtr = n+1;
  291. return kOkFileRC;
  292. }
  293. //
  294. // the provided buffer was not large enough
  295. //
  296. // m tracks the length of the string
  297. unsigned m = n;
  298. while( n+1 == *bufByteCntPtr )
  299. {
  300. // fill the buffer from the current line
  301. if((rc = _cmFileGetLine(p,buf,bufByteCntPtr)) != kOkFileRC )
  302. return rc;
  303. n = strlen(buf);
  304. m += n;
  305. }
  306. // restore the original file offset
  307. if((rc = cmFileSeek(h,kBeginFileFl,offs)) != kOkFileRC )
  308. return rc;
  309. // add 1 for /0, 1 for /n and 1 to detect buf-too-short
  310. *bufByteCntPtr = m+3;
  311. return kBufTooSmallFileRC;
  312. }
  313. cmFileRC_t cmFileGetLineAuto( cmFileH_t h, cmChar_t** bufPtrPtr, unsigned* bufByteCntPtr )
  314. {
  315. cmFileRC_t rc = kOkFileRC;
  316. bool fl = true;
  317. cmChar_t* buf = *bufPtrPtr;
  318. *bufPtrPtr = NULL;
  319. while(fl)
  320. {
  321. fl = false;
  322. switch( rc = cmFileGetLine(h,buf,bufByteCntPtr) )
  323. {
  324. case kOkFileRC:
  325. {
  326. *bufPtrPtr = buf;
  327. }
  328. break;
  329. case kBufTooSmallFileRC:
  330. buf = cmMemResizeZ(cmChar_t,buf,*bufByteCntPtr);
  331. fl = true;
  332. break;
  333. default:
  334. cmMemFree(buf);
  335. break;
  336. }
  337. }
  338. return rc;
  339. }
  340. cmFileRC_t cmFileReadChar( cmFileH_t h, char* buf, unsigned cnt )
  341. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  342. cmFileRC_t cmFileReadUChar( cmFileH_t h, unsigned char* buf, unsigned cnt )
  343. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  344. cmFileRC_t cmFileReadShort( cmFileH_t h, short* buf, unsigned cnt )
  345. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  346. cmFileRC_t cmFileReadUShort( cmFileH_t h, unsigned short* buf, unsigned cnt )
  347. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  348. cmFileRC_t cmFileReadLong( cmFileH_t h, long* buf, unsigned cnt )
  349. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  350. cmFileRC_t cmFileReadULong( cmFileH_t h, unsigned long* buf, unsigned cnt )
  351. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  352. cmFileRC_t cmFileReadInt( cmFileH_t h, int* buf, unsigned cnt )
  353. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  354. cmFileRC_t cmFileReadUInt( cmFileH_t h, unsigned int* buf, unsigned cnt )
  355. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  356. cmFileRC_t cmFileReadFloat( cmFileH_t h, float* buf, unsigned cnt )
  357. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  358. cmFileRC_t cmFileReadDouble( cmFileH_t h, double* buf, unsigned cnt )
  359. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  360. cmFileRC_t cmFileReadBool( cmFileH_t h, bool* buf, unsigned cnt )
  361. { return cmFileRead(h,buf,sizeof(buf[0])*cnt); }
  362. cmFileRC_t cmFileWriteChar( cmFileH_t h, const char* buf, unsigned cnt )
  363. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  364. cmFileRC_t cmFileWriteUChar( cmFileH_t h, const unsigned char* buf, unsigned cnt )
  365. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  366. cmFileRC_t cmFileWriteShort( cmFileH_t h, const short* buf, unsigned cnt )
  367. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  368. cmFileRC_t cmFileWriteUShort( cmFileH_t h, const unsigned short* buf, unsigned cnt )
  369. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  370. cmFileRC_t cmFileWriteLong( cmFileH_t h, const long* buf, unsigned cnt )
  371. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  372. cmFileRC_t cmFileWriteULong( cmFileH_t h, const unsigned long* buf, unsigned cnt )
  373. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  374. cmFileRC_t cmFileWriteInt( cmFileH_t h, const int* buf, unsigned cnt )
  375. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  376. cmFileRC_t cmFileWriteUInt( cmFileH_t h, const unsigned int* buf, unsigned cnt )
  377. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  378. cmFileRC_t cmFileWriteFloat( cmFileH_t h, const float* buf, unsigned cnt )
  379. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  380. cmFileRC_t cmFileWriteDouble( cmFileH_t h, const double* buf, unsigned cnt )
  381. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  382. cmFileRC_t cmFileWriteBool( cmFileH_t h, const bool* buf, unsigned cnt )
  383. { return cmFileWrite(h,buf,sizeof(buf[0])*cnt); }
  384. cmFileRC_t cmFilePrint( cmFileH_t h, const cmChar_t* text )
  385. {
  386. cmFile_t* p = _cmFileHandleToPtr(h);
  387. errno = 0;
  388. if( fputs(text,p->fp) < 0 )
  389. return _cmFileError(p,kPrintFailFileRC,errno,"File print failed");
  390. return kOkFileRC;
  391. }
  392. cmFileRC_t cmFileVPrintf( cmFileH_t h, const cmChar_t* fmt, va_list vl )
  393. {
  394. cmFile_t* p = _cmFileHandleToPtr(h);
  395. if( vfprintf(p->fp,fmt,vl) < 0 )
  396. return _cmFileError(p,kPrintFailFileRC,errno,"File print failed");
  397. return kOkFileRC;
  398. }
  399. cmFileRC_t cmFilePrintf( cmFileH_t h, const cmChar_t* fmt, ... )
  400. {
  401. va_list vl;
  402. va_start(vl,fmt);
  403. cmFileRC_t rc = cmFileVPrintf(h,fmt,vl);
  404. va_end(vl);
  405. return rc;
  406. }