Path: blob/master/modules/dnn/src/torch/THDiskFile.cpp
16337 views
#include "../precomp.hpp"1#include "THGeneral.h"2#include "THDiskFile.h"3#include "THFilePrivate.h"45namespace TH6{78typedef struct THDiskFile__9{10THFile file;1112FILE *handle;13int isNativeEncoding;14int longSize;1516} THDiskFile;1718static int THDiskFile_isOpened(THFile *self)19{20THDiskFile *dfself = (THDiskFile*)self;21return (dfself->handle != NULL);22}2324/* workaround mac osx lion ***insane*** fread bug */25#ifdef __APPLE__26static size_t fread__(void *ptr, size_t size, size_t nitems, FILE *stream)27{28size_t nread = 0;29while(!feof(stream) && !ferror(stream) && (nread < nitems))30nread += fread((char*)ptr+nread*size, size, std::min<size_t>(2147483648UL/size, nitems-nread), stream);31return nread;32}33#else34#define fread__ fread35#endif3637#define READ_WRITE_METHODS(TYPE, TYPEC, ASCII_READ_ELEM, ASCII_WRITE_ELEM) \38static long THDiskFile_read##TYPEC(THFile *self, TYPE *data, long n) \39{ \40THDiskFile *dfself = (THDiskFile*)(self); \41long nread = 0L; \42\43THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file"); \44THArgCheck(dfself->file.isReadable, 1, "attempt to read in a write-only file"); \45\46if(dfself->file.isBinary) \47{ \48nread = fread__(data, sizeof(TYPE), n, dfself->handle); \49if(!dfself->isNativeEncoding && (sizeof(TYPE) > 1) && (nread > 0)) \50THDiskFile_reverseMemory(data, data, sizeof(TYPE), nread); \51} \52else \53{ \54long i; \55for(i = 0; i < n; i++) \56{ \57ASCII_READ_ELEM; /* increment here result and break if wrong */ \58} \59if(dfself->file.isAutoSpacing && (n > 0)) \60{ \61int c = fgetc(dfself->handle); \62if( (c != '\n') && (c != EOF) ) \63ungetc(c, dfself->handle); \64} \65} \66\67if(nread != n) \68{ \69dfself->file.hasError = 1; /* shouldn't we put hasError to 0 all the time ? */ \70if(!dfself->file.isQuiet) \71THError("read error: read %ld blocks instead of %ld", nread, n);\72} \73\74return nread; \75}7677static int THDiskFile_mode(const char *mode, int *isReadable, int *isWritable)78{79*isReadable = 0;80*isWritable = 0;81if(strlen(mode) == 1)82{83if(*mode == 'r')84{85*isReadable = 1;86return 1;87}88else if(*mode == 'w')89{90*isWritable = 1;91return 1;92}93}94else if(strlen(mode) == 2)95{96if(mode[0] == 'r' && mode[1] == 'w')97{98*isReadable = 1;99*isWritable = 1;100return 1;101}102}103return 0;104}105106static void THDiskFile_seek(THFile *self, long position)107{108THDiskFile *dfself = (THDiskFile*)(self);109110THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");111112#if defined(_WIN64)113if(_fseeki64(dfself->handle, (__int64)position, SEEK_SET) < 0)114#elif defined(_WIN32)115if(fseek(dfself->handle, (long)position, SEEK_SET) < 0)116#else117if(fseeko(dfself->handle, (off_t)position, SEEK_SET) < 0)118#endif119{120dfself->file.hasError = 1;121if(!dfself->file.isQuiet)122THError("unable to seek at position %ld", position);123}124}125126static void THDiskFile_seekEnd(THFile *self)127{128THDiskFile *dfself = (THDiskFile*)(self);129130THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");131132#if defined(_WIN64)133if(_fseeki64(dfself->handle, 0L, SEEK_END) < 0)134#elif defined(_WIN32)135if(fseek(dfself->handle, 0L, SEEK_END) < 0)136#else137if(fseeko(dfself->handle, 0L, SEEK_END) < 0)138#endif139{140dfself->file.hasError = 1;141if(!dfself->file.isQuiet)142THError("unable to seek at end of file");143}144}145146static long THDiskFile_position(THFile *self)147{148THDiskFile *dfself = (THDiskFile*)(self);149THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");150151#if defined(_WIN64)152__int64 offset = _ftelli64(dfself->handle);153#elif defined(_WIN32)154long offset = ftell(dfself->handle);155#else156off_t offset = ftello(dfself->handle);157#endif158if (offset > -1)159return (long)offset;160else if(!dfself->file.isQuiet)161THError("unable to obtain disk file offset (maybe a long overflow occurred)");162163return 0;164}165166static void THDiskFile_close(THFile *self)167{168THDiskFile *dfself = (THDiskFile*)(self);169THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");170fclose(dfself->handle);171dfself->handle = NULL;172}173174/* Little and Big Endian */175176static void THDiskFile_reverseMemory(void *dst, const void *src, long blockSize, long numBlocks)177{178if(blockSize != 1)179{180long halfBlockSize = blockSize/2;181char *charSrc = (char*)src;182char *charDst = (char*)dst;183long b, i;184for(b = 0; b < numBlocks; b++)185{186for(i = 0; i < halfBlockSize; i++)187{188char z = charSrc[i];189charDst[i] = charSrc[blockSize-1-i];190charDst[blockSize-1-i] = z;191}192charSrc += blockSize;193charDst += blockSize;194}195}196}197198int THDiskFile_isLittleEndianCPU(void)199{200int x = 7;201char *ptr = (char *)&x;202203if(ptr[0] == 0)204return 0;205else206return 1;207}208209int THDiskFile_isBigEndianCPU(void)210{211return(!THDiskFile_isLittleEndianCPU());212}213214void THDiskFile_nativeEndianEncoding(THFile *self)215{216THDiskFile *dfself = (THDiskFile*)(self);217THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");218dfself->isNativeEncoding = 1;219}220221void THDiskFile_littleEndianEncoding(THFile *self)222{223THDiskFile *dfself = (THDiskFile*)(self);224THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");225dfself->isNativeEncoding = THDiskFile_isLittleEndianCPU();226}227228void THDiskFile_bigEndianEncoding(THFile *self)229{230THDiskFile *dfself = (THDiskFile*)(self);231THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");232dfself->isNativeEncoding = !THDiskFile_isLittleEndianCPU();233}234235/* End of Little and Big Endian Stuff */236237void THDiskFile_longSize(THFile *self, int size)238{239THDiskFile *dfself = (THDiskFile*)(self);240THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");241THArgCheck(size == 0 || size == 4 || size == 8, 1, "Invalid long size specified");242dfself->longSize = size;243}244245void THDiskFile_noBuffer(THFile *self)246{247THDiskFile *dfself = (THDiskFile*)(self);248THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");249if (setvbuf(dfself->handle, NULL, _IONBF, 0)) {250THError("error: cannot disable buffer");251}252}253254static void THDiskFile_free(THFile *self)255{256THDiskFile *dfself = (THDiskFile*)(self);257if(dfself->handle)258fclose(dfself->handle);259THFree(dfself);260}261262/* Note that we do a trick */263READ_WRITE_METHODS(unsigned char, Byte,264nread = fread(data, 1, n, dfself->handle); break,265nwrite = fwrite(data, 1, n, dfself->handle); break)266267READ_WRITE_METHODS(char, Char,268nread = fread(data, 1, n, dfself->handle); break,269nwrite = fwrite(data, 1, n, dfself->handle); break)270271READ_WRITE_METHODS(short, Short,272int ret = fscanf(dfself->handle, "%hd", &data[i]); if(ret <= 0) break; else nread++,273int ret = fprintf(dfself->handle, "%hd", data[i]); if(ret <= 0) break; else nwrite++)274275READ_WRITE_METHODS(int, Int,276int ret = fscanf(dfself->handle, "%d\n\r", &data[i]); if(ret <= 0) break; else nread++,277int ret = fprintf(dfself->handle, "%d", data[i]); if(ret <= 0) break; else nwrite++)278279/*READ_WRITE_METHODS(long, Long,280int ret = fscanf(dfself->handle, "%ld", &data[i]); if(ret <= 0) break; else nread++,281int ret = fprintf(dfself->handle, "%ld", data[i]); if(ret <= 0) break; else nwrite++)*/282283READ_WRITE_METHODS(float, Float,284int ret = fscanf(dfself->handle, "%g", &data[i]); if(ret <= 0) break; else nread++,285int ret = fprintf(dfself->handle, "%.9g", data[i]); if(ret <= 0) break; else nwrite++)286287READ_WRITE_METHODS(double, Double,288int ret = fscanf(dfself->handle, "%lg", &data[i]); if(ret <= 0) break; else nread++,289int ret = fprintf(dfself->handle, "%.17g", data[i]); if(ret <= 0) break; else nwrite++)290291292/* For Long we need to rewrite everything, because of the special management of longSize */293static long THDiskFile_readLong(THFile *self, int64 *data, long n)294{295THDiskFile *dfself = (THDiskFile*)(self);296long nread = 0L;297298THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");299THArgCheck(dfself->file.isReadable, 1, "attempt to read in a write-only file");300301if(dfself->file.isBinary)302{303if(dfself->longSize == 0 || dfself->longSize == sizeof(int64))304{305nread = fread__(data, sizeof(int64), n, dfself->handle);306if(!dfself->isNativeEncoding && (sizeof(int64) > 1) && (nread > 0))307THDiskFile_reverseMemory(data, data, sizeof(int64), nread);308} else if(dfself->longSize == 4)309{310nread = fread__(data, 4, n, dfself->handle);311if(!dfself->isNativeEncoding && (nread > 0))312THDiskFile_reverseMemory(data, data, 4, nread);313long i;314for(i = nread; i > 0; i--)315data[i-1] = ((int *)data)[i-1];316}317else /* if(dfself->longSize == 8) */318{319int big_endian = !THDiskFile_isLittleEndianCPU();320int32_t *buffer = (int32_t*)THAlloc(8*n);321if (!buffer)322THError("can not allocate buffer");323nread = fread__(buffer, 8, n, dfself->handle);324long i;325for(i = nread; i > 0; i--)326data[i-1] = buffer[2*(i-1) + big_endian];327THFree(buffer);328if(!dfself->isNativeEncoding && (nread > 0))329THDiskFile_reverseMemory(data, data, 4, nread);330}331}332else333{334long i;335for(i = 0; i < n; i++)336{337long d;338int ret = fscanf(dfself->handle, "%ld", &d); if(ret <= 0) break; else nread++;339data[i] = d;340}341if(dfself->file.isAutoSpacing && (n > 0))342{343int c = fgetc(dfself->handle);344if( (c != '\n') && (c != EOF) )345ungetc(c, dfself->handle);346}347}348349if(nread != n)350{351dfself->file.hasError = 1; /* shouldn't we put hasError to 0 all the time ? */352if(!dfself->file.isQuiet)353THError("read error: read %ld blocks instead of %ld", nread, n);354}355356return nread;357}358359360static long THDiskFile_readString(THFile *self, const char *format, char **str_)361{362THDiskFile *dfself = (THDiskFile*)(self);363THArgCheck(dfself->handle != NULL, 1, "attempt to use a closed file");364THArgCheck(dfself->file.isReadable, 1, "attempt to read in a write-only file");365THArgCheck((strlen(format) >= 2 ? (format[0] == '*') && (format[1] == 'a' || format[1] == 'l') : 0), 2, "format must be '*a' or '*l'");366367/* note: the string won't survive long, as it is copied into lua */368/* so 1024 is not that big... */369#define TBRS_BSZ 1024L370371if(format[1] == 'a')372{373char *p = (char*)THAlloc(TBRS_BSZ);374long total = TBRS_BSZ;375long pos = 0L;376377for (;;)378{379if(total-pos == 0) /* we need more space! */380{381total += TBRS_BSZ;382p = (char*)THRealloc(p, total);383}384if (p == NULL)385THError("read error: failed to allocate buffer");386pos += fread(p+pos, 1, total-pos, dfself->handle);387if (pos < total) /* eof? */388{389if(pos == 0L)390{391THFree(p);392dfself->file.hasError = 1;393if(!dfself->file.isQuiet)394THError("read error: read 0 blocks instead of 1");395396*str_ = NULL;397return 0;398}399*str_ = p;400return pos;401}402}403}404else405{406char *p = (char*)THAlloc(TBRS_BSZ);407long total = TBRS_BSZ;408long pos = 0L;409long size;410411for (;;)412{413if(total-pos <= 1) /* we can only write '\0' in there! */414{415total += TBRS_BSZ;416p = (char*)THRealloc(p, total);417}418if (p == NULL)419THError("read error: failed to allocate buffer");420if (fgets(p+pos, total-pos, dfself->handle) == NULL) /* eof? */421{422if(pos == 0L)423{424THFree(p);425dfself->file.hasError = 1;426if(!dfself->file.isQuiet)427THError("read error: read 0 blocks instead of 1");428429*str_ = NULL;430return 0;431}432*str_ = p;433return pos;434}435size = strlen(p+pos);436if (size == 0L || (p+pos)[size-1] != '\n')437{438pos += size;439}440else441{442pos += size-1L; /* do not include `eol' */443*str_ = p;444return pos;445}446}447}448449*str_ = NULL;450return 0;451}452453THFile *THDiskFile_new(const std::string &name, const char *mode, int isQuiet)454{455static struct THFileVTable vtable = {456THDiskFile_isOpened,457458THDiskFile_readByte,459THDiskFile_readChar,460THDiskFile_readShort,461THDiskFile_readInt,462THDiskFile_readLong,463THDiskFile_readFloat,464THDiskFile_readDouble,465THDiskFile_readString,466467THDiskFile_seek,468THDiskFile_seekEnd,469THDiskFile_position,470THDiskFile_close,471THDiskFile_free472};473474int isReadable;475int isWritable;476FILE *handle;477THDiskFile *self;478479THArgCheck(THDiskFile_mode(mode, &isReadable, &isWritable), 2, "file mode should be 'r','w' or 'rw'");480481CV_Assert(isReadable && !isWritable);482483#ifdef _MSC_VER484if (fopen_s(&handle, name.c_str(), "rb") != 0)485handle = NULL;486#else487handle = fopen(name.c_str(),"rb");488#endif489490if(!handle)491{492if(isQuiet)493return 0;494else495THError("cannot open <%s> in mode %c%c", name.c_str(), (isReadable ? 'r' : ' '), (isWritable ? 'w' : ' '));496}497498self = (THDiskFile*)THAlloc(sizeof(THDiskFile));499if (!self)500THError("cannot allocate memory for self");501502self->handle = handle;503self->isNativeEncoding = 1;504self->longSize = 0;505506self->file.vtable = &vtable;507self->file.isQuiet = isQuiet;508self->file.isReadable = isReadable;509self->file.isWritable = isWritable;510self->file.isBinary = 0;511self->file.isAutoSpacing = 1;512self->file.hasError = 0;513514return (THFile*)self;515}516517}518519520