/* * $Id: file2mat.c 6618 2015-12-01 16:25:38Z spm $ * John Ashburner */ /* Memory mapping is used by this module. For more information on this, see: http://www.mathworks.com/company/newsletters/digest/mar04/memory_map.html */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include "mex.h" #ifdef SPM_WIN32 #include #include #include HANDLE hFile, hMapping; typedef char *caddr_t; #if defined _FILE_OFFSET_BITS && _FILE_OFFSET_BITS == 64 #define stat _stati64 #define fstat _fstati64 #define open _open #define close _close #if defined _MSC_VER #define size_t __int64 #else #define size_t unsigned long long #endif #endif #else #include #include #include #define size_t unsigned long long #endif /* http://en.wikipedia.org/wiki/Page_(computing)#Determining_the_page_size_in_a_program http://msdn.microsoft.com/en-us/library/aa366763(VS.85).aspx */ int page_size() { int size = 0; #if defined (_WIN32) || defined (_WIN64) SYSTEM_INFO info; GetSystemInfo (&info); size = (int)info.dwAllocationGranularity; #else size = sysconf(_SC_PAGESIZE); #endif return size; } #define MXDIMS 256 static long long icumprod[MXDIMS], ocumprod[MXDIMS]; static void get_1_sat(mwSize ndim, mwSize idim[], int *iptr[], unsigned char idat[], mwSize odim[], unsigned char odat[], int indi, int indo) { mwIndex i; if (ndim == 0) { for(i=0; i>3]>>(tmp&7))&1; } } else { for(i=0; iaddr) { #ifdef SPM_WIN32 sts = UnmapViewOfFile((LPVOID)(map->addr)); if (sts == 0) werror("Memory Map (UnmapViewOfFile)",GetLastError()); #else sts = munmap(map->addr, map->len); if (sts == -1) werror("Memory Map (munmap)",errno); #endif map->addr = NULL; } } const double *getpr(const mxArray *ptr, const char nam[], int len, int *n) { char s[128]; mxArray *arr; arr = mxGetField(ptr,0,nam); if (arr == (mxArray *)0) { (void)sprintf(s,"'%s' field is missing.", nam); mexErrMsgTxt(s); } if (!mxIsNumeric(arr) && !mxIsLogical(arr)) { (void)sprintf(s,"'%s' field is non-numeric.", nam); mexErrMsgTxt(s); } if (!mxIsDouble(arr)) { (void)sprintf(s,"'%s' field is not double precision.", nam); mexErrMsgTxt(s); } if (len>=0) { *n = mxGetM(arr)*mxGetN(arr); if (*n != len) { (void)sprintf(s,"'%s' field should have %d elements (has %d).", nam, len, *n); mexErrMsgTxt(s); } } else { *n = mxGetM(arr)*mxGetN(arr); if (*n > -len) { (void)sprintf(s,"'%s' field should have a maximum of %d elements (has %d).", nam, -len, *n); mexErrMsgTxt(s); } } return (double *)mxGetData(arr); } void do_map_file(const mxArray *ptr, MTYPE *map) { int n; int i, dtype; #ifdef SPM_WIN32 ULONGLONG offset = 0; #else off_t offset = 0; #endif const double *pr; mxArray *arr; size_t siz; if (!mxIsStruct(ptr)) mexErrMsgTxt("Not a structure."); dtype = (int)(getpr(ptr, "dtype", 1, &n)[0]); for(i=0; idtype = &table[i]; break; } } if (map->dtype == NULL) mexErrMsgTxt("Unrecognised 'dtype' value."); pr = getpr(ptr, "dim", -MXDIMS, &n); map->ndim = n; siz = 1; for(i=0; indim; i++) { map->dim[i] = (mwSize)fabs(pr[i]); siz = siz*map->dim[i]; } /* Avoid overflow if possible */ if (map->dtype->bytes % 8) siz = (map->dtype->bytes*siz+7)/8; else siz = siz*(map->dtype->bytes/8); /* On 32bit platforms, cannot map more than 2^31-1 bytes */ if ((sizeof(map->data) == 4) && (siz > 2147483647ULL)) mexErrMsgTxt("The total number of bytes mapped is too large."); pr = getpr(ptr, "be",1, &n); #ifdef SPM_BIGENDIAN map->swap = (int)pr[0]==0; #else map->swap = (int)pr[0]!=0; #endif pr = getpr(ptr, "offset",1, &n); #ifdef SPM_WIN32 map->off = (ULONGLONG)pr[0]; #else map->off = (off_t)pr[0]; #endif if (map->off < 0) map->off = 0; arr = mxGetField(ptr,0,"fname"); if (arr == (mxArray *)0) mexErrMsgTxt("Cant find fname."); if (mxIsChar(arr)) { char *buf = NULL; int fd; struct stat stbuf; if ((buf = mxArrayToString(arr)) == NULL) { mxFree(buf); mexErrMsgTxt("Cant get filename."); } if ((fd = open(buf, O_RDONLY)) == -1) { mxFree(buf); mexErrMsgTxt("Cant open file."); } if (fstat(fd, &stbuf) == -1) { (void)close(fd); mxFree(buf); mexErrMsgTxt("Cant get file size."); } if (stbuf.st_size < siz + map->off) { (void)close(fd); mxFree(buf); mexErrMsgTxt("File is smaller than the dimensions say it should be."); } offset = map->off % page_size(); map->len = siz + (size_t)offset; map->off = map->off - offset; #ifdef SPM_WIN32 (void)close(fd); /* http://msdn.microsoft.com/library/default.asp? url=/library/en-us/fileio/base/createfile.asp */ hFile = CreateFile( buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL); mxFree(buf); if (hFile == NULL) werror("Memory Map (CreateFile)",GetLastError()); /* http://msdn.microsoft.com/library/default.asp? url=/library/en-us/fileio/base/createfilemapping.asp */ hMapping = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL); (void)CloseHandle(hFile); if (hMapping == NULL) werror("Memory Map (CreateFileMapping)",GetLastError()); /* http://msdn.microsoft.com/library/default.asp? url=/library/en-us/fileio/base/mapviewoffile.asp */ map->addr = (caddr_t)MapViewOfFile( hMapping, FILE_MAP_READ, (DWORD)(map->off >> 32), (DWORD)(map->off), map->len); (void)CloseHandle(hMapping); if (map->addr == NULL) werror("Memory Map (MapViewOfFile)",GetLastError()); #else map->addr = mmap( (caddr_t)0, map->len, PROT_READ, MAP_SHARED, fd, map->off); (void)close(fd); mxFree(buf); if (map->addr == (void *)-1) werror("Memory Map (mmap)",errno); #endif } map->data = (void *)((caddr_t)map->addr + offset); } void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { MTYPE map; void *idat; int i; mwSize odim[MXDIMS], *idim, ndim; int *iptr[MXDIMS]; int one[1]; one[0] = 1; if (nrhs<2 || nlhs>1) mexErrMsgTxt("Incorrect usage."); do_map_file(prhs[0], &map); ndim = map.ndim; idim = map.dim; idat = map.data; if (ndim >= MXDIMS) mexErrMsgTxt("Too many dimensions."); /* if (nrhs > ndim+1) mexErrMsgTxt("Index exceeds matrix dimensions (1)."); */ for(i=0;i((ichannels; ocumprod[0] = 1; for(i=0; ibytes==1 && i==1) icumprod[i+1] = ((icumprod[i+1]+7)/8)*8; } if (map.dtype->channels == 1) { plhs[0] = mxCreateNumericArray(ndim,odim,map.dtype->clss,mxREAL); #ifdef SPM_WIN32 /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa366801.aspx */ __try { #endif map.dtype->func(ndim-1, idim, iptr, idat, odim, mxGetData(plhs[0])); #ifdef SPM_WIN32 } __except(GetExceptionCode()==EXCEPTION_IN_PAGE_ERROR ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { mexErrMsgTxt("An exception occured while accessing the data."); } #endif if (map.swap) map.dtype->swap(ocumprod[ndim],mxGetData(plhs[0])); } else if (map.dtype->channels == 2) { plhs[0] = mxCreateNumericArray(ndim,odim,map.dtype->clss,mxCOMPLEX); (map.dtype->func)(ndim-1, idim, iptr, idat, odim, mxGetData(plhs[0]),mxGetImagData(plhs[0])); if (map.swap) { map.dtype->swap(ocumprod[ndim],mxGetData(plhs[0])); map.dtype->swap(ocumprod[ndim],mxGetImagData(plhs[0])); } } do_unmap_file(&map); }