home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Science⁄Math / VideoToolbox / VideoToolboxSources / ReadMATLABFile.c < prev    next >
Encoding:
Text File  |  1993-12-14  |  11.8 KB  |  410 lines  |  [TEXT/KAHL]

  1. /*
  2. ReadMATLABFile.c - load/save a matrix from/to a MATLAB data file.
  3. These functions allow any C program to read and write MATLAB data files.
  4.  
  5. int SaveMatDoubles(FILE *f,char *name,long rows,long cols
  6.     ,double *real,double *imag);            // write doubles as 8-byte DOUBLES
  7. int SaveMatShorts(FILE *f,char *name,long rows,long cols
  8.     ,short *real,short *imag);                // write shorts as shorts
  9. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  10.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  11. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  12.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  13. int LoadNamedMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  14.     ,double **real,double **imag);            // read 8-byte DOUBLES into doubles
  15. int LoadNamedMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  16.     ,short **real,short **imag);            // read 8-byte DOUBLES into shorts
  17.  
  18. All the routines assume an open file, and return an error if they hit end of
  19. file. The SaveXXX routines append a matrix to the existing file. The LoadNextXXX
  20. routines read the next matrix from the file, advancing the file pointer.
  21. SaveXXX and LoadNextXXX can be called repeatedly until they fail (e.g. end of
  22. file is reached). The LoadNamedXXX routines first rewind the file and then scan
  23. it until they find a matrix whose name matches that supplied, or end of file is
  24. reached. The file pointer is left at the end of that matrix. Calling LoadNameXXX
  25. repeatedly will read the same matrix every time: the first instance of the named
  26. matrix.
  27.  
  28. The LoadXXX and SaveXXX routines return 0 if successful and a positive nonzero
  29. integer if they fail.  The two array pointers will be NULL after calling LoadXXX
  30. unless they are loaded. The second (imaginary) pointer will be NULL unless the
  31. matrix was complex. Similarly, when you call SaveXXX you indicate a real matrix
  32. by supplying a NULL second pointer.
  33.  
  34. There is a slight asymmetry here that you should be aware of. SaveMatShorts()
  35. produces a (compact) MATLAB file made up of shorts, but the
  36. LoadXXXMatIntoShorts() will only read a (big) MATLAB file made up of 8-byte
  37. doubles. So you won't always be able to read from C the file you wrote from C.
  38. The reason for this is that while the MATLAB "Load" command supports all the
  39. MATLAB file formats, the MATLAB "Save" command has no provision for specifying
  40. (binary) file formats and thus always uses format type 0, 8-byte short doubles,
  41. so I didn't bother to implement any routines to read any other format. (It would
  42. be easy to add this capability, if it were needed.)
  43.  
  44. EXAMPLES:
  45. This example loads the first two matrices from a MATLAB file:
  46.  
  47.     FILE *f;
  48.     char name[64];
  49.     long rows,cols;
  50.     double *xr,*xi;
  51.     short *mr,*mi;
  52.     int error;
  53.     f = fopen("foo.mat","rb");
  54.     error=LoadNextMatIntoDoubles(f,name,&rows,&cols,&xr,&xi);
  55.      error=LoadNextMatIntoShorts(f,name,&rows,&cols,&mr,&mi);
  56.     fclose(f);
  57.     free(xr);
  58.     free(xi);
  59.     free(mr);
  60.     free(mi);
  61.  
  62. Alternatively, you can read a specific matrix, by name, from the file:
  63.  
  64.     error=LoadNamedMatIntoDoubles(f,"Put name here",&rows,&cols,&xr,&xi);
  65.      error=LoadNamedMatIntoShorts(f,"Put name here",&rows,&cols,&mr,&mi);
  66.  
  67. This example creates a MATLAB file containing four matrices:
  68.  
  69.     FILE *fp;
  70.     double xyz[1000],ar[1000],ai[1000];
  71.     short m[100],n[100];
  72.     fp = fopen("bar.mat","wb");
  73.     SetFileInfo("bar.mat",'MATW','MATL');
  74.     error=SaveMatDoubles(fp,"xyz",2,3,xyz,NULL);    // real
  75.     error=SaveMatShorts(fp,"m",2,3,m,NULL);            // real
  76.     error=SaveMatDoubles(fp,"a",5,5,ar,ai);            // complex
  77.     error=SaveMatShorts(fp,"mc",2,3,m,n);            // complex
  78.     fclose(fp);
  79.  
  80.  
  81. HISTORY:
  82. 11-3-86 J.N. Little wrote loadmat.c and savemat.c
  83.  
  84. [14-Feb-91] jmb -- Added support for MPW C 3.x and THINK C.
  85.  
  86. 1/4/93    dgp Renamed to MatLab.c. DOUBLE is now used soley within the new
  87. WriteXXX and ReadXXX subroutines. C users now only deal with double and short
  88. arrays; necessary conversions are done behind the scenes. double is faster and
  89. more convenient for Macintosh programming than the 8-byte short double used in
  90. the MATLAB files. Added support for file format 3: signed short ints. Omitted
  91. the imagf flag since it's redundant. Omitted the type argument by supplying
  92. several user-callable front ends, each tailored to a particular number type.
  93.  
  94. 2/93 dgp Renamed to ReadMatLabFile.c
  95.  
  96. 6/22-25/93 jas & dgp wrote LoadNamedMat. Renamed LoadMatShorts and
  97. LoadMatDoubles to LoadNextMatIntoShorts and LoadNextMatIntoDoubles. Added
  98. LoadNamedMatIntoShorts and LoadNamedMatIntoDoubles.
  99.  
  100. 12/93 dgp Renamed to ReadMATLABFile.c
  101. */
  102. #include "VideoToolbox.h"
  103. #include <assert.h>
  104.  
  105. double *ReadDoubles(FILE *f,long elements,char *name);
  106. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name);
  107. int WriteDoubles(FILE *f,long elements,char *name,double *d);
  108. int WriteShorts(FILE *f,long elements,char *name,short *d);
  109. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type);
  110. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  111.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  112. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  113.     ,void **real,void **imag,long *fileType,long desiredNumberType);
  114.  
  115. typedef struct {
  116.      long type;        /* type */
  117.      long rows;        /* row dimension */
  118.      long cols;        /* column dimension */
  119.      long imagf;    /* flag indicating imag part */
  120.      long namlen;    /* name length (including NULL) */
  121. } Fmatrix;
  122.  
  123. /* From cmex.h */
  124. // MATLAB files with number format 0 use 8-byte floating point numbers, which
  125. // we'll call DOUBLE.
  126. #undef DOUBLE
  127. #ifdef THINK_C
  128.     #define DOUBLE short double
  129. #else
  130.     #define DOUBLE double
  131. #endif
  132.  
  133. int LoadNextMatIntoDoubles(FILE *f,char *name,long *rows,long *cols
  134.     ,double **real,double **imag)
  135. {
  136.     long fileType,desiredNumberType=0;
  137.     
  138.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  139.         ,&fileType,desiredNumberType);
  140. }
  141.     
  142. int LoadNextMatIntoShorts(FILE *f,char *name,long *rows,long *cols
  143.     ,short **real,short **imag)
  144. {
  145.     long fileType,desiredNumberType=3;
  146.     
  147.     return LoadNextMat(f,name,rows,cols,(void **)real,(void **)imag
  148.         ,&fileType,desiredNumberType);
  149. }
  150.  
  151. int LoadNamedMatIntoDoubles(FILE *f,const char *name,long *rows,long *cols
  152.     ,double **real,double **imag)
  153. {
  154.     long fileType,desiredNumberType=0;
  155.     
  156.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  157.         ,&fileType,desiredNumberType);
  158. }
  159.     
  160. int LoadNamedMatIntoShorts(FILE *f,const char *name,long *rows,long *cols
  161.     ,short **real,short **imag)
  162. {
  163.     long fileType,desiredNumberType=3;
  164.     
  165.     return LoadNamedMat(f,name,rows,cols,(void **)real,(void **)imag
  166.         ,&fileType,desiredNumberType);
  167. }
  168.  
  169. int SaveMatDoubles(FILE *f,char *name,long rows,long cols,double *real,double *imag)
  170. {
  171.     return SaveMat(f,name,rows,cols,real,imag,0);
  172. }
  173.  
  174. int SaveMatShorts(FILE *f,char *name,long rows,long cols,short *real,short *imag)
  175. {
  176.     return SaveMat(f,name,rows,cols,real,imag,30);
  177. }
  178.     
  179. int LoadNamedMat(FILE *f,const char *name,long *rows,long *cols
  180.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  181. {
  182.     char curname[100];
  183.     int error;
  184.     
  185.     rewind(f);
  186.     while(1){
  187.         error=LoadNextMat(f,curname,rows,cols,real,imag,fileType,desiredNumberType);
  188.         if(error)return error;
  189.         if(strcmp(curname,name)==0)break;
  190.         if(*real!=NULL){
  191.             free(*real);
  192.             *real=NULL;
  193.         }
  194.         if(*imag!=NULL){
  195.             free(*imag);
  196.             *imag=NULL;
  197.         }
  198.     }
  199.     return 0;
  200. }
  201.  
  202. int LoadNextMat(FILE *f,char *name,long *rows,long *cols
  203.     ,void **real,void **imag,long *fileType,long desiredNumberType)
  204. {
  205.     Fmatrix    x;
  206.     long elements,namlen,imagf,numberFormat;
  207.     
  208.     *real=*imag=NULL;
  209.     name[0]=0;
  210.     if(feof(f))return 1;
  211.  
  212.     // Get Fmatrix structure from file
  213.     if (fread((char *)&x,sizeof(Fmatrix),1,f) != 1) return 2;
  214.     *fileType = x.type;
  215.     *rows = x.rows;
  216.     *cols = x.cols;
  217.     namlen = x.namlen;
  218.     elements = x.rows * x.cols;
  219.  
  220.     if(x.type/1000!=1)return 3;        // not Macintosh-compatible binary format
  221.     if(x.type/100%10!=0)return 4;    // transposed
  222.     numberFormat=x.type/10%10;
  223.     if(numberFormat!=0)return 5;    // not 8-byte doubles
  224.  
  225.     // Get matrix name from file
  226.     if (fread(name,sizeof(char),namlen,f) != namlen) return 6;
  227.     
  228.     // Get Real part of matrix from file
  229.     switch(desiredNumberType){
  230.     case 0:
  231.         *real=ReadDoubles(f,elements,name);
  232.         break;
  233.     case 3:
  234.         *real=ReadDoublesIntoShorts(f,elements,name);
  235.         break;
  236.     default:
  237.         *real=NULL;
  238.     }
  239.     if(*real==NULL)return 7;
  240.  
  241.     // Get Imag part of matrix from file, if it exists
  242.     if (x.imagf) {
  243.         switch(desiredNumberType){
  244.         case 0:
  245.             *imag=ReadDoubles(f,elements,name);
  246.             break;
  247.         case 3:
  248.             *imag=ReadDoublesIntoShorts(f,elements,name);
  249.             break;
  250.         }
  251.         if(*imag==NULL){
  252.             free(*real);
  253.             *real=NULL;
  254.             return 8;
  255.         }
  256.     }
  257.     return 0;
  258. }
  259.  
  260. int SaveMat(FILE *f,char *name,long rows,long cols,void *real,void *imag,long type)
  261. {
  262.     Fmatrix    x;
  263.     long elements;
  264.     int error;
  265.     int fileFormat;
  266.     
  267.     type%=100;    // not transposed
  268.     type+=1000;    // indicate Macintosh-compatible binary format
  269.     x.type = type;
  270.     x.rows = rows;
  271.     x.cols = cols;
  272.     if(imag==NULL)x.imagf=0;
  273.     else x.imagf=1;
  274.     x.namlen = strlen(name) + 1;
  275.     elements = x.rows * x.cols;
  276.  
  277.     if(x.type/1000!=1)return 9;        // not Macintosh-compatible binary format
  278.     if(x.type/100%10!=0)return 10;    // transposed
  279.     fileFormat=x.type/10%10;
  280.     if(fileFormat!=0 && fileFormat!=3)return 11; // neither 8-byte double, nor short
  281.  
  282.     fwrite(&x,sizeof(Fmatrix),1,f);
  283.     fwrite(name,sizeof(char),(long)x.namlen,f);
  284.     switch(fileFormat){
  285.     case 0:
  286.         error=WriteDoubles(f,elements,name,real);
  287.         break;
  288.     case 3:
  289.         error=WriteShorts(f,elements,name,real);
  290.         break;
  291.     default:
  292.         error=1;
  293.     }
  294.     if(error)return 12;
  295.     if (imag!=NULL) {
  296.         switch(fileFormat){
  297.         case 0:
  298.             error=WriteDoubles(f,elements,name,imag);
  299.             break;
  300.         case 3:
  301.             error=WriteShorts(f,elements,name,imag);
  302.             break;
  303.         default:
  304.             error=1;
  305.         }
  306.         if(error)return 13;
  307.     }
  308.     return 0;
  309. }
  310.  
  311. // Reads DOUBLES (8-byte short doubles) into doubles
  312. double *ReadDoubles(FILE *f,long elements,char *name)
  313. {
  314.     DOUBLE *D;
  315.     double *d;
  316.     long i,n,j;
  317.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  318.     
  319.     assert(sizeof(DOUBLE)==8);
  320.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  321.     if(D==NULL){
  322.         printf("\nError: not enough room for buffer\n");
  323.         return NULL;
  324.     }
  325.     if (!(d = (double *)malloc(elements*sizeof(*d)))) {
  326.         printf("\nError: Variable %s too big to load\n",name);
  327.         return NULL;
  328.     }
  329.     for(i=0;i<elements;){
  330.         if(dSize<elements-i)n=dSize;
  331.         else n=elements-i;
  332.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  333.             free(d);
  334.             free(D);
  335.             return NULL;
  336.         }
  337.         for(j=0;j<n;j++)d[i++]=D[j];    // convert DOUBLE to double
  338.     }
  339.     free(D);
  340.     return d;
  341. }
  342.  
  343. // Reads DOUBLES (8-byte short doubles) into shorts
  344. short *ReadDoublesIntoShorts(FILE *f,long elements,char *name)
  345. {
  346.     DOUBLE *D;
  347.     short *d;
  348.     long i,n,j;
  349.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  350.     
  351.     assert(sizeof(DOUBLE)==8);
  352.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  353.     if(D==NULL){
  354.         printf("\nError: not enough room for buffer\n");
  355.         return NULL;
  356.     }
  357.     if (!(d = (short *)malloc(elements*sizeof(*d)))) {
  358.         printf("\nError: Variable %s too big to load\n",name);
  359.         return NULL;
  360.     }
  361.     for(i=0;i<elements;){
  362.         if(dSize<elements-i)n=dSize;
  363.         else n=elements-i;
  364.         if(fread(D,sizeof(DOUBLE),n,f) != n) {
  365.             free(d);
  366.             free(D);
  367.             return NULL;
  368.         }
  369.         for(j=0;j<n;j++)d[i++]=D[j];    // convert DOUBLE to short
  370.     }
  371.     free(D);
  372.     return d;
  373. }
  374.  
  375. // Writes doubles as DOUBLES (8-byte short doubles)
  376. int WriteDoubles(FILE *f,long elements,char *name,double *d)
  377. {
  378.     DOUBLE *D;
  379.     long i,n,j;
  380.     const dSize=2048/sizeof(DOUBLE);    // Can be whatever you want. Bigger is faster.
  381.     
  382.     assert(sizeof(DOUBLE)==8);
  383.     if (d==NULL) return 14;
  384.     D=(DOUBLE *)malloc(dSize*sizeof(DOUBLE));
  385.     if(D==NULL){
  386.         printf("\nError: not enough room for buffer\n");
  387.         return 15;
  388.     }
  389.     for(i=0;i<elements;){
  390.         if(dSize<elements-i)n=dSize;
  391.         else n=elements-i;
  392.         for(j=0;j<n;j++)D[j]=d[i++];    // convert double to DOUBLE
  393.         if(fwrite(D,sizeof(DOUBLE),n,f) != n) {
  394.             free(D);
  395.             return 16;
  396.         }
  397.     }
  398.     free(D);
  399.     return 0;
  400. }
  401.  
  402. // Writes shorts as shorts
  403. int WriteShorts(FILE *f,long elements,char *name,short *d)
  404. {
  405.     assert(sizeof(short)==2);
  406.     if (d==NULL) return 17;
  407.     if(fwrite(d,sizeof(short),elements,f) != elements) return 18;
  408.     return 0;
  409. }
  410.