📄 text.cpp
字号:
{
// set us to the next text block
ptb = GetRun(-1);
ich = ptb->_cch;
}
else
{
//we're at the very beginning of the text, just return NULL
cchValidReverse = 0;
return NULL;
}
}
AssertSz(CbOfCch(ich) <= ptb->_cbBlock,
"CTxtPtr::GetPchReverse(): _ich bigger than block");
pchBase = ptb->_pch + ich;
// Check to see if we need to skip over gap. Recall that
// the game may come anywhere in the middle of a block,
// so if the current ich (note, no underscore, we want
// the active ich) is at least one char past the gap, then recompute
// pchBase by adding the size of the gap (so that it's after
// the gap). This differs from GetPch(), which works forward and
// wants pchBase to include the gap size if ich is at the gap, let
// alone one or more chars past it.
//
// Also figure out the count of valid characters. It's
// either the count of characters from the beginning of the
// text block, i.e. ich, or the count of characters from the
// end of the buffer gap.
cchValidReverse = ich; // Default for ich <= gap offset
cchTemp = ich - CchOfCb(ptb->_ibGap); // Calculate displacement
if(cchTemp > 0) // Positive: pchBase is after gap
{
cchValidReverse = cchTemp;
pchBase += CchOfCb(ptb->_cbBlock) - ptb->_cch; // Add in gap size
}
if ( pcchValid ) // if client needs forward length
{
if ( cchTemp > 0 )
cchTemp = ich - ptb->_cch;
else
cchTemp = -cchTemp;
*pcchValid = cchTemp;
}
Assert(cchValidReverse);
return pchBase;
}
/*
* CTxtPtr::BindToCp(cp)
*
* @mfunc
* set cached _cp = cp (or nearest valid value)
*
* @rdesc
* _cp actually set
*
* @comm
* This method overrides CRunPtrBase::BindToCp to keep _cp up to date
* correctly.
*
* @devnote
* Do *not* call this method when high performance is needed; use
* AdvanceCp() instead, which advances from 0 or from the cached
* _cp, depending on which is closer.
*/
DWORD CTxtPtr::BindToCp(
DWORD cp) //@parm char position to bind to
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::BindToCp");
_cp = CRunPtrBase::BindToCp(cp);
// We want to be able to use this routine to fix up things so we don't
// check invariants on entry.
_TEST_INVARIANT_
return _cp;
}
/*
* CTxtPtr::SetCp(cp)
*
* @mfunc
* 'efficiently' sets cp by advancing from current position or from 0,
* depending on which is closer
*
* @rdesc
* cp actually set to
*/
DWORD CTxtPtr::SetCp(
DWORD cp) //@parm char position to set to
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::SetCp");
AdvanceCp(cp - _cp);
return _cp;
}
/*
* CTxtPtr::AdvanceCp(cch)
*
* @mfunc
* Advance cp by cch characters
*
* @rdesc
* Actual number of characters advanced by
*
* @comm
* We override CRunPtrBase::AdvanceCp so that the cached _cp value
* can be correctly updated and so that the advance can be made
* from the cached _cp or from 0, depending on which is closer.
*
* @devnote
* It's also easy to bind at the end of the story. So an improved
* optimization would bind there if 2*(_cp + cch) > _cp + text length.
*/
LONG CTxtPtr::AdvanceCp(
LONG cch) // @parm count of chars to advance by
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::AdvanceCp");
if(!IsValid()) // No runs yet, so don't go
return 0; // anywhere
const LONG cpSave = _cp; // Save entry _cp
LONG cp = cpSave + cch; // Requested target cp (maybe < 0)
if(cp < cpSave/2) // Closer to 0 than cached cp
{
cp = max(cp, 0); // Don't undershoot
_cp = CRunPtrBase::BindToCp(cp);
}
else
_cp += CRunPtrBase::AdvanceCp(cch); // exist
// NB! the invariant check needs to come at the end; we may be
// moving 'this' text pointer in order to make it valid again
// (for the floating range mechanism).
_TEST_INVARIANT_
return _cp - cpSave; // cch this CTxtPtr moved
}
/*
* CTxtPtr::GetText(cch, pch)
*
* @mfunc
* get a range of cch characters starting at this text ptr. A literal
* copy is made, i.e., with no CR -> CRLF and WCH_EMBEDDING -> ' '
* translations. For these translations, see CTxtPtr::GetPlainText()
*
* @rdesc
* count of characters actually copied
*
* @comm
* Doesn't change this text ptr
*/
LONG CTxtPtr::GetText(
LONG cch, //@parm Count of characters to get
TCHAR * pch) //@parm Buffer to copy the text into
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::GetText");
LONG cchSave = cch;
LONG cchValid;
const TCHAR *pchRead;
CTxtPtr tp(*this);
_TEST_INVARIANT_
// Use tp to read valid blocks of text until all the requested
// text is read or until the end of story is reached.
while( cch )
{
pchRead = tp.GetPch(cchValid);
if(!pchRead) // No more text
break;
cchValid = min(cchValid, cch);
CopyMemory(pch, pchRead, cchValid*sizeof(TCHAR));
pch += cchValid;
cch -= cchValid;
tp.AdvanceCp(cchValid);
}
return cchSave - cch;
}
/*
* CTxtPtr::GetPlainText(cchBuff, pch, cpMost, fTextize)
*
* @mfunc
* Copy up to cchBuff characters or up to cpMost, whichever comes
* first, translating lone CRs into CRLFs. Move this text ptr just
* past the last character processed. If fTextize, copy up to but
* not including the first WCH_EMBEDDING char. If not fTextize,
* replace WCH_EMBEDDING by a blank since RichEdit 1.0 does.
*
* @rdesc
* Count of characters copied
*
* @comm
* An important feature is that this text ptr is moved just past the
* last char copied. In this way, the caller can conveniently read
* out plain text in bufferfuls of up to cch chars, which is useful for
* stream I/O. This routine won't copy the final CR even if cpMost
* is beyond it.
*/
LONG CTxtPtr::GetPlainText(
LONG cchBuff, //@parm Buffer cch
TCHAR * pch, //@parm Buffer to copy text into
LONG cpMost, //@parm Largest cp to get
BOOL fTextize) //@parm True if break on WCH_EMBEDDING
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::GetPlainText");
LONG cch = cchBuff; // Countdown counter
LONG cchValid; // Valid ptr cch
LONG cchT; // Temporary cch
unsigned ch; // Current char
const TCHAR *pchRead; // Backing-store ptr
_TEST_INVARIANT_
AdjustCpCRLF(); // Be sure we start on an EOP bdy
LONG cchText = _ped->GetAdjustedTextLength();
cpMost = min(cpMost, cchText); // Don't write final CR
if((LONG)GetCp() >= cpMost)
return 0;
while(cch > 0) // While room in buffer
{
if(!(pchRead = GetPch(cchValid))) // No more chars available
break; // so we're out of here
cchT = GetCp() + cchValid - cpMost;
if(cchT > 0) // Don't overshoot
{
cchValid -= cchT;
if(cchValid <= 0)
break; // Nothing left before cpMost
}
for(cchT = 0; cch > 0 && cchT < cchValid; cchT++, cch--)
{
ch = *pch++ = *pchRead++; // Copy next char (but don't
if(IsASCIIEOP(ch)) // count it yet)
{
AdvanceCp(cchT); // Move up to CR
if(cch < 2) // No room for LF, so don't
goto done; // count CR either
// Bypass EOP w/o worrying about
cchT = AdvanceCpCRLF(); // buffer gaps and blocks
if(cchT > 2) // Translate CRCRLF to ' '
{ // Usually copied count exceeds
Assert(cchT == 3); // internal count, but CRCRLFs
*(pch - 1) = ' '; // reduce the relative increase:
} // NB: error for EM_GETTEXTLENGTHEX
else // CRLF or lone CR
{ // Store LF in both cases for
*(pch - 1) = CR; // Be sure it's a CR not a VT,
#ifndef MACPORT // FF, or lone LF
*pch++ = LF; // Windows. No LF for Mac
cch--; // One less for target buffer
#endif
}
cch--; // CR (or ' ') copied
cchT = 0; // Don't AdvanceCp() more below
break; // Go get new pchRead & cchValid
}
else if(ch == WCH_EMBEDDING) // Object lives here
{
if(fTextize) // Break on WCH_EMBEDDING
{
AdvanceCp(cchT); // Move this text ptr up to
goto done; // WCH_EMBEDDING and return
}
*(pch - 1) = ' '; // Replace embedding char by ' '
} // since RichEdit 1.0 does
#ifdef PWD_JUPITER
else if(ch == CELL)
{
// GuyBark Jupiter: We're writing out plain text here, so DON'T write
// out RichEdit's own value for cell delimiters in tables. Instead
// just write out a tab. This allows rows to be pasted into PExcel.
*(pch - 1) = TAB;
}
// GuyBark JupiterJ 49481: J users do not want this action...
// ARULM: Globalize: This is just plain weird, but the Japanese dont want
// this conversion to happen on Japanese machines. Whatever...
else if((ch == LDBLQUOTE || ch == RDBLQUOTE) && !g_fHasJapanSupport)
{
// Left and right dbl quotes have code points in the 1252 code page.
// This means unless we take action here, we output these left and
// right characters in the text file. This is fine when re-opened in
// PWord or Word97. But if the text file is opened in Notepage, it
// simply displays the square blocks for these extended characters.
// That's not what we want, so always output the straight dbl quotes
// for these characters when saving as text. This mimics Word97.
*(pch - 1) = '"';
}
else if((ch == LQUOTE || ch == RQUOTE) && !g_fHasJapanSupport)
{
// The above also applies to left and right single quotes.
*(pch - 1) = '\'';
}
// #endif // !FAREAST
else if(ch == PWD_CRLFINCELL)
{
// We've hit the special character used to represent CRLF in
// table cells. Just is always followed by another space. This
// isn't what Word97 does, (it starts a new line here), but who cares?
*(pch - 1) = ' ';
}
#endif // PWD_JUPITER
}
AdvanceCp(cchT);
}
done:
return cchBuff - cch;
}
/*
* CTxtPtr::AdvanceCpCRLF()
*
* @mfunc
* Advance text pointer by one character, safely advancing
* over CRLF, CRCRLF, and UTF-16 combinations
*
* @rdesc
* Number of characters text pointer has been moved by
*
* @future
* Advance over Unicode combining marks
*/
LONG CTxtPtr::AdvanceCpCRLF()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::AdvanceCpCRLF");
_TEST_INVARIANT_
DWORD cpSave = _cp;
TCHAR ch = GetChar(); // Char on entry
TCHAR ch1 = NextChar(); // Advance to and get next char
BOOL fTwoCRs = FALSE;
if(ch == CR)
{
if(ch1 == CR && _cp < GetTextLength())
{
fTwoCRs = TRUE; // Need at least 3 chars to
ch1 = NextChar(); // have CRCRLF at end
}
if(ch1 == LF)
AdvanceCp(1); // Bypass CRLF
else if(fTwoCRs)
AdvanceCp(-1); // Only bypass one CR of two
AssertSz(_ped->Get10Mode() || _cp == cpSave + 1,
"CTxtPtr::AdvanceCpCRLF: EOP isn't a single char");
}
// To support UTF-16, include the following code
// if ((ch & UTF16) == UTF16_TRAIL) // Landed on UTF-16 trail word
// AdvanceCp(1); // Bypass UTF-16 trail word
return _cp - cpSave; // # chars bypassed
}
/*
* CTxtPtr::NextChar()
*
* @mfunc
* Increment this text ptr and return char it points at
*
* @rdesc
* Next char
*/
TCHAR CTxtPtr::NextChar()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::NextChar");
_TEST_INVARIANT_
AdvanceCp(1);
return GetChar();
}
/*
* CTxtPtr::PrevChar()
*
* @mfunc
* Decrement this text ptr and return char it points at
*
* @rdesc
* Previous char
*/
TCHAR CTxtPtr::PrevChar()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::PrevChar");
_TEST_INVARIANT_
return AdvanceCp(-1) ? GetChar() : 0;
}
/*
* CTxtPtr::BackupCpCRLF()
*
* @mfunc
* Backup text pointer by one character, safely backing up
* over CRLF, CRCRLF, and UTF-16 combinations
*
* @rdesc
* Number of characters text pointer has been moved by
*
* @future
* Backup over Unicode combining marks
*/
LONG CTxtPtr::BackupCpCRLF()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CTxtPtr::BackupCpCRLF");
_TEST_INVARIANT_
DWORD cpSave = _cp;
TCHAR ch = PrevChar(); // Advance to and get previous char
if (ch == LF && // Try to back up 1 char in any case
(_cp && PrevChar() != CR || // If LF, does prev char = CR?
_cp && PrevChar() != CR)) // If so, does its prev char = CR?
{ // (CRLF at BOD checks CR twice; OK)
AdvanceCp(1); // Backed up too far
}
// To support UTF-16, include the following code
// if ((ch & UTF16) == UTF16_TRAIL) // Landed on UTF-16 trail word
// AdvanceCp(-1); // Backup to UTF-16 lead word
return _cp - cpSave; // - # chars this CTxtPtr moved
}
/*
* CTxtPtr::AdjustCpCRLF()
*
* @mfunc
* Adjust the position of this text pointer to the beginning of a CRLF,
* CRCRLF, or UTF-16 combination if it is in the middle of such a
* combination
*
* @rdesc
* Number of characters text pointer has been moved by
*
* @future
* Adjust to beginning of sequence containing Unicode combining marks
*/
LONG CTxtPtr::AdjustCpCRLF()
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -