libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

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. }