⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 stdio.cpp

📁 evc 下的flash播放器源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		// Leftovers at the end
		const int cch = ::MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, 
			pchSrc, cbSrc,
			pwchDst, cchAvailable);
		if (0 == cch)
		{
			*pcchEmitted = cchOut;
			return FALSE;
		}
		cchOut += cch;
		pwchDst += cch;
		cchAvailable -= cch;
	}

	*pcchEmitted = cchOut;
	return TRUE;
}


// Expanding newlines into CRNL sequences, sans Unicode

BOOL CookOutputTextAA(const char* pchSrc, unsigned cbSrc, unsigned cbNewlines,
				      char* pchDst, unsigned cchAvailable, unsigned* pcchEmitted )
{
	unsigned cchOut = 0; // count of characters written to pwchOut

	if (cbNewlines > 0 && cbSrc > 0)
	{
		// Seeking newlines in the sourcetext, one line at a time
		// Thought: since we have cbNewlines, could use strchr here,
		// decrementing a count of the # of newlines found.
		// That approach would easily transition to an approach
		// where the initial cbNewline count also saved offsets.

		const char* pch = pchSrc;
		unsigned cb = cbSrc;
		while (cb--)
		{
			if (*pch++ == '\n') //$ BUGBUG DBCS, again
			{
				// Copy/convert everything but the newline
				const int cbLine = cbSrc - cb - 1;
				if (cbLine > 0)
				{
					memcpy(pchDst, pchSrc, cbLine);
					cchOut += cbLine;
					pchDst += cbLine;
					cchAvailable -= cbLine;
				}
				// Emit a 'cooked' newline sequence to replace the newline
				*pchDst++ = '\r';
				*pchDst++ = '\n';
				cchOut += 2;
				cchAvailable -= 2;

				cbSrc = cb;
				pchSrc = pch;
			}
		}
	}
	if (cbSrc > 0)
	{
		// Leftovers at the end
		memcpy(pchDst, pchSrc, cbSrc);
		cchOut += cbSrc;
		pchDst += cbSrc;
		cchAvailable -= cbSrc;
	}

	*pcchEmitted = cchOut;
	return TRUE;
}


// Count the number of newlines in source

unsigned CountNewlines(const char* pch, unsigned cb)
{
	//$ BUGBUG DBCS - sigh -
	// can't use strchr loop because pchOut not NUL terminated

	unsigned cbNewlines = 0;
	while (cb--)
		if (*pch++ == '\n')
			++cbNewlines;
	return cbNewlines;
}


CXFileStream::CXFileStream()
	: _h(NULL), _fUseUnicode(FALSE), _cchCRsEaten(0)
{
	// Since this object is reused, do all real init in Open
}


CXFileStream::~CXFileStream()
{
	Close();
}


BOOL CXFileStream::LoadReadBuffer(unsigned cbHint)
{
	const int cchReadQuantum = 512; // used instead of 'cbHint'

	if (NULL == _h)
		return FALSE;

	if (!_fCooked)
	{
		// 1 character, 1 byte. Life is simple and good.

		if (!RequireBuffer(cchReadQuantum)) // set _{c,p}bBuffer
			return FALSE;

		DWORD cbActuallyRead = 0L;
		if (!::ReadFile(_h, _pbBuffer, cchReadQuantum, &cbActuallyRead, NULL))
		{
			//$ BUGBUG better error logging?
			return FALSE;
		}
		if (0 == cbActuallyRead)
			return FALSE;
		_cbActual = cbActuallyRead;
	}
	else
	{
		// Require space for reading text from file,
		// plus space for cooking text: CRNL->NL, possibly Unicode->MBCS.

		// cbRequired: one of the (1+cchReadQuantum)*cbChar is for the WCHAR input,
		// and one is for the MBCS output,
		// pessimistically assuming that every wchar will expand into a 2-byte dbcs sequence.
		// While this seems pointless, given that dbcs input would blow SIOD out of the water,
		// that might change someday....

		const unsigned cbOneChar = _fUseUnicode ? sizeof(WCHAR) : sizeof(char);
		const unsigned cbRead = cchReadQuantum*cbOneChar;
		const unsigned cbRequired = 2*((1+cchReadQuantum)*cbOneChar);

		if (!RequireBuffer(cbRequired)) // set _{c,p}bBuffer
			return FALSE;

		// Fetch source text into tail-end of buffer

		const int ibOffset = (1+cchReadQuantum)* cbOneChar;
		BYTE* pbInPreConvert = _pbBuffer+ibOffset;
		DWORD cbActuallyRead = 0L;
		if (!::ReadFile(_h, pbInPreConvert, cbRead, &cbActuallyRead, NULL))
			return FALSE;
		if (0 == cbActuallyRead)
			return FALSE;

		BOOL fHadTrailingCR;
		unsigned cchCRsEaten;
		if (_fUseUnicode)
		{
			// Convert to MBCS, flattening CRLF sequences to LF as we go
			const unsigned cch = cbActuallyRead/sizeof(WCHAR);
			((WCHAR*)pbInPreConvert)[cch] = 0;
			if (!CookInputTextWA((const WCHAR*)pbInPreConvert, cch, 
				(char*)_pbBuffer, ibOffset, &_cbActual, &fHadTrailingCR, &cchCRsEaten))
				return FALSE;
		}
		else
		{
			// Copy and flatten
			((char*)pbInPreConvert)[cbActuallyRead] = 0;
			if (!CookInputTextAA((const char*)pbInPreConvert, cbActuallyRead, 
				(char*)_pbBuffer, ibOffset, &_cbActual, &fHadTrailingCR, &cchCRsEaten))
				return FALSE;
		}

		// Special evil case: if last character was a CR, 
		// we might have a CRLF sequence crossing the boundary of the read buffer.

		if (fHadTrailingCR)
		{
			// Peek ahead to see if it is so.
			// (Assumes we're working from a disk file. Were this a live IPC channel,
			// we'd delete the trailing CR, then save the pending-possible-CRLF
			// state to resolve in the next Read call.)

			BOOL fFoundNL;
			if (_fUseUnicode)
			{
				WCHAR chReadAhead;
				if (!::ReadFile(_h, &chReadAhead, sizeof(WCHAR), &cbActuallyRead, NULL))
					return FALSE;
				fFoundNL = (sizeof(WCHAR) == cbActuallyRead && __T('\n') == chReadAhead);
			}
			else
			{
				char chReadAhead;
				if (!::ReadFile(_h, &chReadAhead, sizeof(char), &cbActuallyRead, NULL))
					return FALSE;
				fFoundNL = (sizeof(char) == cbActuallyRead && '\n' == chReadAhead);
			}

			if (fFoundNL)
			{
				_pbBuffer[_cbActual] = '\n';
				++cchCRsEaten;
			}
			if (cbActuallyRead > 0 && !fFoundNL)
				::SetFilePointer(_h, -1*cbActuallyRead, NULL, FILE_CURRENT);
		}

		_cchCRsEaten = cchCRsEaten;
	}

	return (_cbActual > 0);
}


void CXFileStream::Write(const BYTE* pbOut, unsigned cbOut, unsigned* pcbOutActual)
{
	if (NULL == _h)
		return;

	if (_fAppending)
	{
		// All writes move to end of file
		::SetFilePointer(_h, 0, NULL, FILE_END);
	}
	else if (_fReading && _cbActual > 0)
	{
		// Write must move back to point of last "read" character
		int ibOffset = _cbActual - _ibCurrent;
		if (_fCooked && ibOffset > 0)
			ibOffset += CountNewlines((const char*)(_pbBuffer+_ibCurrent), ibOffset);
		if (_fUseUnicode && ibOffset > 0)
			ibOffset *= sizeof(WCHAR);
		if (ibOffset > 0)
			::SetFilePointer(_h, -ibOffset, NULL, FILE_CURRENT);
	}

	if (_fReading)
		ResetReadBuffer();

	if (!_fCooked)
	{
		DWORD cbActualWrite = 0L;
		if (!::WriteFile(_h, pbOut, cbOut, &cbActualWrite, NULL))
		{
			//$ BUGBUG better error logging?
			*pcbOutActual = 0;
			return;
		}
		*pcbOutActual = cbActualWrite;
	}
	else
	{
		// Use "cooked" to emit Unicode text, expand LF to CRLF.

		const unsigned cbNewlines = CountNewlines((const char*)pbOut, cbOut);
		const unsigned cbOneChar = _fUseUnicode ? sizeof(WCHAR) : sizeof(char);

		CLocalTempBuffer buf;
		if (!buf.Init( (cbOut+cbNewlines)*cbOneChar ))
		{
			*pcbOutActual = 0;
			return;
		}
		BYTE* pbOutConverted = buf.GetBuffer();

		unsigned cch = 0;
		if (_fUseUnicode)
		{
			if (!CookOutputTextAW((const char*)pbOut, cbOut, cbNewlines,
				(WCHAR*)pbOutConverted, cbOut+cbNewlines, &cch))
			{
				*pcbOutActual = 0;
				return;
			}
		}
		else
		{
			if (!CookOutputTextAA((const char*)pbOut, cbOut, cbNewlines,
				(char*)pbOutConverted, cbOut+cbNewlines, &cch))
			{
				*pcbOutActual = 0;
				return;
			}
		}

		DWORD cbActualWrite = 0L;
		if (!::WriteFile(_h, pbOutConverted, cbOneChar*cch, &cbActualWrite, NULL))
		{
			//$ BUGBUG better error logging?
			*pcbOutActual = 0;
			return;
		}
		*pcbOutActual = cbActualWrite;
	}
}


unsigned CXFileStream::TellUnbuffered()
{
	unsigned ib = ::SetFilePointer(_h, 0, NULL, FILE_CURRENT);

	if (_fUseUnicode)
	{
		ib /= sizeof(WCHAR);
		ib -= 1; // for BOM
	}

	return ib;
}


unsigned CXFileStream::Tell()
{
	if (NULL == _h)
		return 0;

	unsigned ib = TellUnbuffered();

	if (_fReading)
	{
		// Adjust for characters in read buffer
		ib -= _cbActual;
		// Adjust again for CR characters missing from read buffer
		if (_fCooked)
			ib -= _cchCRsEaten;
		// Move forward by characters "read" in read buffer
		ib += _ibCurrent;
	}

	return ib;
}


BOOL CXFileStream::Seek(int ibOffset, int nType)
{
	if (NULL == _h)
		return FALSE;

	DWORD dwMethod;
	switch (nType)
	{
	case SEEK_CUR:
		dwMethod = FILE_CURRENT;
		break;
	case SEEK_END:
		dwMethod = FILE_END;
		break;
	case SEEK_SET:
	default:
		dwMethod = FILE_BEGIN;
		break;
	}

	//
	// File offsets vs. stream buffer offsets
	// ====================================================
	//         ^         ^          ^  
	//         |         |          |
	//         |         |          |
	//         ibInFile  |          ibInFile 
	//      - _cbActual  |          (TRUE file offset)
	//   - _cchCRsEaten  |
	//                   ibInFile
	//                 - _cbActual
	//                 - _cchCRsEaten
	//                 + _ibCurrent
	//                  (VIRTUAL file offset)
	//
	// Note that for the purposes of these calculations
	// we place all the imaginary lost bytes represented by _cchCRsEaten
	// between the last buffered-read byte - _pbBuffer+_cbActual-1 - and ibInFile.
	// There is no attempt to associate a particular lost CR 
	// with a particular offset in the file.

	if (_fReading )
	{
		if (nType != SEEK_END)
		{
			// If the new offset lands within the read-buffer, "seek" takes place therein

			const unsigned ibInFile = TellUnbuffered();
			const unsigned ibStartBuf = ibInFile - _cbActual - _cchCRsEaten;
			const unsigned ibVirtual = ibStartBuf + _ibCurrent;

			unsigned ibNewVirtual;
			if (nType == SEEK_CUR)
			{
				// Need signed arithmetic, since relative offset is signed
				ibNewVirtual = (unsigned)((int)ibVirtual + ibOffset);
			}
			else // SEEK_SET
			{
				ibNewVirtual = (unsigned)ibOffset;
			}

			if (ibNewVirtual >= ibStartBuf && ibNewVirtual < ibInFile)
			{
				_ibCurrent = ibNewVirtual - ibStartBuf;
				return TRUE;
			}
		}

		// Untested hypothesis: it is worthwhile to preserve sequential-read behavior
		// when presenting reads and seeks to the filesystem.
		// Adjust the relative seek offset to compensate for read-buffer position,
		// i.e. the characters buffered but not yet "read,"
		// since true file offset is ahead of virtual offset.
		// Could instead convert all relative seeks to absolute seeks,
		// but then the lack of true CRLF adjustment might bite harder.

		if (nType == SEEK_CUR)
		{
			const unsigned dbRelative = _cbActual - _ibCurrent;
			ibOffset -= ((int)dbRelative + (int)_cchCRsEaten);
		}

		// Having adjusted for the seek-ptr offset as necessary, 
		// discard the now useless readbuffer

		ResetReadBuffer();
	}

	if (_fUseUnicode)
	{
		int nGuard = ibOffset; // test for overflow
		ibOffset *= sizeof(WCHAR);

		if (  ((ibOffset > 0) && (ibOffset < nGuard))
			||((ibOffset < 0) && (ibOffset > nGuard)) )
			return FALSE;

		if (dwMethod != FILE_END)
		{
			nGuard = ibOffset;
			ibOffset += sizeof(WCHAR); // for BOM
			if (ibOffset < nGuard) // test again for overflow
				return FALSE;
		}
	}

	if (0xffffffff == ::SetFilePointer(_h, ibOffset, NULL, dwMethod))
		return FALSE;
	return TRUE;
}


void CXFileStream::Close()
{
	ResetReadBuffer();
	ReleaseBuffer();

	if (NULL == _h)
		return;

	::CloseHandle(_h);
	_h = NULL;
}


/* MODE flags for an opened file:
 *  "r": read       "w": write      "a": append
 *  "r+": read/write                "w+": open empty for read/write
 *  "a+": read/append

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -