"Fossies" - the Fresh Open Source Software Archive

Member "AutoHotkey_L-1.1.33.09/source/TextIO.h" (8 May 2021, 10063 Bytes) of package /windows/misc/AutoHotkey_L-1.1.33.09.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "TextIO.h" see the Fossies "Dox" file reference documentation.

    1 #pragma once
    2 
    3 #define TEXT_IO_BLOCK   8192
    4 
    5 #ifndef CP_UTF16
    6 #define CP_UTF16        1200 // the codepage of UTF-16LE
    7 #endif
    8 
    9 #ifdef UNICODE
   10 #define W_OR_A(n)   n##W
   11 #else
   12 #define W_OR_A(n)   n##A
   13 #endif
   14 
   15 #define TEOF ((TCHAR)EOF)
   16 
   17 #include <locale.h> // For _locale_t, _create_locale and _free_locale.
   18 
   19 extern UINT g_ACP;
   20 
   21 // VS2005 and later come with Unicode stream IO in the C runtime library, but it doesn't work very well.
   22 // For example, it can't read the files encoded in "system codepage" by using
   23 // wide-char version of the functions such as fgetws(). The characters were not translated to
   24 // UTF-16 properly. Although we can create some workarounds for it, but that will make
   25 // the codes even hard to maintain.
   26 class TextStream
   27 {
   28 public:
   29     enum {
   30         // open modes
   31           READ
   32         , WRITE
   33         , APPEND
   34         , UPDATE
   35         , USEHANDLE = 0x10000000 // Used by BIF_FileOpen/FileObject. High value avoids conflict with the flags below, which can't change because it would break scripts.
   36         , ACCESS_MODE_MASK = READ|WRITE|APPEND|UPDATE|USEHANDLE
   37 
   38         // EOL translations
   39         , EOL_CRLF = 0x00000004 // read: CRLF to LF. write: LF to CRLF.
   40         , EOL_ORPHAN_CR = 0x00000008 // read: CR to LF (when the next character isn't LF)
   41 
   42         // write byte order mark when open for write
   43         , BOM_UTF8 = 0x00000010
   44         , BOM_UTF16 = 0x00000020
   45 
   46         // shared accesses
   47         , SHARE_READ = 0x00000100
   48         , SHARE_WRITE = 0x00000200
   49         , SHARE_DELETE = 0x00000400
   50         , SHARE_ALL = SHARE_READ|SHARE_WRITE|SHARE_DELETE
   51     };
   52 
   53     TextStream()
   54         : mFlags(0), mCodePage(-1), mLength(0), mBuffer(NULL), mPos(NULL), mLastRead(0)
   55     {
   56         SetCodePage(CP_ACP);
   57     }
   58     virtual ~TextStream()
   59     {
   60         if (mBuffer)
   61             free(mBuffer);
   62         //if (mLocale)
   63         //  _free_locale(mLocale);
   64         // Close() isn't called here, it will rise a "pure virtual function call" exception.
   65     }
   66 
   67     bool Open(LPCTSTR aFileSpec, DWORD aFlags, UINT aCodePage = CP_ACP);
   68     void Close()
   69     {
   70         FlushWriteBuffer();
   71         _Close();
   72     }
   73 
   74     DWORD Write(LPCTSTR aBuf, DWORD aBufLen = 0);
   75     DWORD Write(LPCVOID aBuf, DWORD aBufLen);
   76     DWORD Read(LPTSTR aBuf, DWORD aBufLen, int aNumLines = 0);
   77     DWORD Read(LPVOID aBuf, DWORD aBufLen);
   78 
   79     DWORD ReadLine(LPTSTR aBuf, DWORD aBufLen)
   80     {
   81         return Read(aBuf, aBufLen, 1);
   82     }
   83 
   84     INT_PTR FormatV(LPCTSTR fmt, va_list ap)
   85     {
   86         CString str;
   87         str.FormatV(fmt, ap);
   88         return Write(str, (DWORD)str.GetLength()) / sizeof(TCHAR);
   89     }
   90     INT_PTR Format(LPCTSTR fmt, ...)
   91     {
   92         va_list ap;
   93         va_start(ap, fmt);
   94         return FormatV(fmt, ap);
   95     }
   96 
   97     bool AtEOF()
   98     // Returns true if there is no more data in the read buffer
   99     // *and* the file pointer is at the end of the file.
  100     {
  101         if (mPos && mPos < mBuffer + mLength)
  102             return false;
  103         __int64 pos = _Tell();
  104         return (pos < 0 || pos >= _Length());
  105     }
  106 
  107     void SetCodePage(UINT aCodePage)
  108     {
  109         if (aCodePage == CP_ACP)
  110             aCodePage = g_ACP; // Required by _create_locale.
  111         //if (!IsValidCodePage(aCodePage)) // Returns FALSE for UTF-16 and possibly other valid code pages, so leave it up to the user to pass a valid codepage.
  112             //return;
  113 
  114         if (mCodePage != aCodePage)
  115         {
  116             // Resist temptation to do the following as a way to avoid having an odd number of bytes in
  117             // the buffer, since it breaks non-seeking devices and actually isn't sufficient for cases
  118             // where the caller uses raw I/O in addition to text I/O (e.g. read one byte then read text).
  119             //RollbackFilePointer();
  120 
  121             mCodePage = aCodePage;
  122             if (!GetCPInfo(aCodePage, &mCodePageInfo))
  123                 mCodePageInfo.LeadByte[0] = NULL;
  124         }
  125     }
  126     UINT GetCodePage() { return mCodePage; }
  127     DWORD GetFlags() { return mFlags; }
  128 
  129 protected:
  130     // IO abstraction
  131     virtual bool    _Open(LPCTSTR aFileSpec, DWORD &aFlags) = 0;
  132     virtual void    _Close() = 0;
  133     virtual DWORD   _Read(LPVOID aBuffer, DWORD aBufSize) = 0;
  134     virtual DWORD   _Write(LPCVOID aBuffer, DWORD aBufSize) = 0;
  135     virtual bool    _Seek(__int64 aDistance, int aOrigin) = 0;
  136     virtual __int64 _Tell() const = 0;
  137     virtual __int64 _Length() const = 0;
  138     
  139     void RollbackFilePointer()
  140     {
  141         if (mPos) // Buffered reading was used.
  142         {
  143             // Discard the buffer and rollback the file pointer.
  144             ptrdiff_t offset = (mPos - mBuffer) - mLength; // should be a value <= 0
  145             _Seek(offset, SEEK_CUR);
  146             // Callers expect the buffer to be cleared (e.g. to be reused for buffered writing), so if
  147             // _Seek fails, the data is simply discarded.  This can probably only happen for non-seeking
  148             // devices such as pipes or the console, which won't typically be both read from and written to:
  149             mPos = NULL;
  150             mLength = 0;
  151         }
  152     }
  153     
  154     void FlushWriteBuffer()
  155     {
  156         if (mLength && !mPos)
  157         {
  158             // Flush write buffer.
  159             _Write(mBuffer, mLength);
  160             mLength = 0;
  161         }
  162         mLastWriteChar = 0;
  163     }
  164 
  165     bool PrepareToWrite()
  166     {
  167         if (!mBuffer)
  168             mBuffer = (BYTE *) malloc(TEXT_IO_BLOCK);
  169         else if (mPos) // Buffered reading was used.
  170             RollbackFilePointer();
  171         return mBuffer != NULL;
  172     }
  173 
  174     bool PrepareToRead()
  175     {
  176         FlushWriteBuffer();
  177         return true;
  178     }
  179 
  180     template<typename TCHR>
  181     DWORD WriteTranslateCRLF(TCHR *aBuf, DWORD aBufLen); // Used by TextStream::Write(LPCSTR,DWORD).
  182 
  183     // Functions for populating the read buffer.
  184     DWORD Read(DWORD aReadSize = TEXT_IO_BLOCK)
  185     {
  186         ASSERT(aReadSize);
  187         if (!mBuffer) {
  188             mBuffer = (BYTE *) malloc(TEXT_IO_BLOCK);
  189             if (!mBuffer)
  190                 return 0;
  191         }
  192         if (mLength + aReadSize > TEXT_IO_BLOCK)
  193             aReadSize = TEXT_IO_BLOCK - mLength;
  194         DWORD dwRead = _Read(mBuffer + mLength, aReadSize);
  195         if (dwRead)
  196             mLength += dwRead;
  197         return mLastRead = dwRead; // The amount read *this time*.
  198     }
  199     bool ReadAtLeast(DWORD aReadSize)
  200     {
  201         if (!mPos)
  202             Read(TEXT_IO_BLOCK);
  203         else if (mPos > mBuffer + mLength - aReadSize) {
  204             ASSERT( (DWORD)(mPos - mBuffer) <= mLength );
  205             mLength -= (DWORD)(mPos - mBuffer);
  206             memmove(mBuffer, mPos, mLength);
  207             Read(TEXT_IO_BLOCK);
  208         }
  209         else
  210             return true;
  211         mPos = mBuffer;
  212         return (mLength >= aReadSize);
  213     }
  214 
  215     __declspec(noinline) bool IsLeadByte(BYTE b) // noinline benchmarks slightly faster.
  216     {
  217         for (int i = 0; i < _countof(mCodePageInfo.LeadByte) && mCodePageInfo.LeadByte[i]; i += 2)
  218             if (b >= mCodePageInfo.LeadByte[i] && b <= mCodePageInfo.LeadByte[i+1])
  219                 return true;
  220         return false;
  221     }
  222 
  223     DWORD mFlags;
  224     DWORD mLength;      // The length of available data in the buffer, in bytes.
  225     DWORD mLastRead;
  226     UINT  mCodePage;
  227     CPINFO mCodePageInfo;
  228     
  229     TCHAR mLastWriteChar;
  230 
  231     union // Pointer to the next character to read in mBuffer.
  232     {
  233         LPBYTE  mPos;
  234         LPSTR   mPosA;
  235         LPWSTR  mPosW;
  236     };
  237     union // Used by buffered/translated IO to hold raw file data. 
  238     {
  239         LPBYTE  mBuffer;
  240         LPSTR   mBufferA;
  241         LPWSTR  mBufferW;
  242     };
  243 };
  244 
  245 
  246 
  247 class TextFile : public TextStream
  248 {
  249 public:
  250     TextFile() : mFile(INVALID_HANDLE_VALUE) {}
  251     virtual ~TextFile() { FlushWriteBuffer(); _Close(); }
  252 
  253     // Text IO methods from TextStream.
  254     using TextStream::Read;
  255     using TextStream::Write;
  256 
  257     // These methods are exported to provide binary file IO.
  258     bool    Seek(__int64 aDistance, int aOrigin)
  259     {
  260         RollbackFilePointer();
  261         FlushWriteBuffer();
  262         return _Seek(aDistance, aOrigin);
  263     }
  264     __int64 Tell()
  265     {
  266         __int64 pos = _Tell();
  267         return (pos == -1) ? -1 : pos + (mPos ? mPos - (mBuffer + mLength) : (ptrdiff_t)mLength);
  268     }
  269     __int64 Length()
  270     {
  271         __int64 len = _Length();
  272         if (!mPos && mLength) // mBuffer contains data to write.
  273         {
  274             // Not len+mLength, since we might not be writing at the end of the file.
  275             // Return the current position plus the amount of buffered data, except
  276             // when that falls short of the current actual length of the file.
  277             __int64 buf_end = _Tell() + mLength;
  278             if (buf_end > len)
  279                 return buf_end;
  280         }
  281         return len;
  282     }
  283     __int64 Length(__int64 aLength)
  284     {
  285         // Truncating the file may mean discarding some of the data in the buffer:
  286         // data read from a position after the new end-of-file, or data which should
  287         // have already been written after the new end-of-file, but has been buffered.
  288         // Calculating how much data should be discarded doesn't seem worthwhile, so
  289         // just flush the buffer:
  290         RollbackFilePointer();
  291         FlushWriteBuffer();
  292         // Since the buffer was just flushed, Tell() vs _Tell() doesn't matter here.
  293         // Otherwise, using Tell() followed by _Seek() below would advance the pointer
  294         // by the amount of buffered data, when the intention is to not move it at all.
  295         __int64 pos = _Tell();
  296         if (!_Seek(aLength, SEEK_SET) || !SetEndOfFile(mFile))
  297             return -1;
  298         // Make sure we do not extend the file again.
  299         _Seek(min(aLength, pos), SEEK_SET);
  300         return _Length();
  301     }
  302     HANDLE  Handle() { RollbackFilePointer(); FlushWriteBuffer(); return mFile; }
  303 protected:
  304     virtual bool    _Open(LPCTSTR aFileSpec, DWORD &aFlags);
  305     virtual void    _Close();
  306     virtual DWORD   _Read(LPVOID aBuffer, DWORD aBufSize);
  307     virtual DWORD   _Write(LPCVOID aBuffer, DWORD aBufSize);
  308     virtual bool    _Seek(__int64 aDistance, int aOrigin);
  309     virtual __int64 _Tell() const;
  310     virtual __int64 _Length() const;
  311 
  312 private:
  313     HANDLE mFile;
  314 };
  315 
  316 
  317 
  318 // TextMem is intended to attach a memory block, which provides code pages and end-of-line conversions (CRLF <-> LF).
  319 // It is used for reading the script data in compiled script.
  320 // Note that TextMem doesn't have any ability to write and seek.
  321 class TextMem : public TextStream
  322 {
  323 public:
  324     // TextMem tmem;
  325     // tmem.Open(TextMem::Buffer(buffer, length), EOL_CRLF, CP_ACP);
  326     struct Buffer
  327     {
  328         Buffer(LPVOID aBuf = NULL, DWORD aBufLen = 0, bool aOwned = true)
  329             : mBuffer((LPBYTE)aBuf), mLength(aBufLen), mOwned(aOwned)
  330         {}
  331         operator LPCTSTR() const { return (LPCTSTR) this; }
  332         LPVOID mBuffer;
  333         DWORD mLength;
  334         bool mOwned;    // If true, the memory will be freed by _Close().
  335     };
  336 
  337     TextMem()
  338     {
  339         mData.mBuffer = NULL;
  340         mData.mLength = 0;
  341         mData.mOwned = false;
  342         mDataPos = NULL;
  343     }
  344     virtual ~TextMem() { _Close(); }
  345 protected:
  346     virtual bool    _Open(LPCTSTR aFileSpec, DWORD &aFlags);
  347     virtual void    _Close();
  348     virtual DWORD   _Read(LPVOID aBuffer, DWORD aBufSize);
  349     virtual DWORD   _Write(LPCVOID aBuffer, DWORD aBufSize);
  350     virtual bool    _Seek(__int64 aDistance, int aOrigin);
  351     virtual __int64 _Tell() const;
  352     virtual __int64 _Length() const;
  353 private:
  354     Buffer mData;
  355     LPBYTE mDataPos;
  356 };