Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

564 lines
19 KiB

  1. // MLLBCons.cpp : Implementation of CMLLBCons
  2. #include "private.h"
  3. #include "mllbcons.h"
  4. #ifdef ASTRIMPL
  5. #include "mlswalk.h"
  6. #endif
  7. #include "mlstrbuf.h"
  8. /////////////////////////////////////////////////////////////////////////////
  9. // Line Break Character Table
  10. const WCHAR awchNonBreakingAtLineEnd[] = {
  11. 0x0028, // LEFT PARENTHESIS
  12. 0x005B, // LEFT SQUARE BRACKET
  13. 0x007B, // LEFT CURLY BRACKET
  14. 0x00AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK
  15. 0x2018, // LEFT SINGLE QUOTATION MARK
  16. 0x201C, // LEFT DOUBLE QUOTATION MARK
  17. 0x2039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK
  18. 0x2045, // LEFT SQUARE BRACKET WITH QUILL
  19. 0x207D, // SUPERSCRIPT LEFT PARENTHESIS
  20. 0x208D, // SUBSCRIPT LEFT PARENTHESIS
  21. 0x226A, // MUCH LESS THAN
  22. 0x3008, // LEFT ANGLE BRACKET
  23. 0x300A, // LEFT DOUBLE ANGLE BRACKET
  24. 0x300C, // LEFT CORNER BRACKET
  25. 0x300E, // LEFT WHITE CORNER BRACKET
  26. 0x3010, // LEFT BLACK LENTICULAR BRACKET
  27. 0x3014, // LEFT TORTOISE SHELL BRACKET
  28. 0x3016, // LEFT WHITE LENTICULAR BRACKET
  29. 0x3018, // LEFT WHITE TORTOISE SHELL BRACKET
  30. 0x301A, // LEFT WHITE SQUARE BRACKET
  31. 0x301D, // REVERSED DOUBLE PRIME QUOTATION MARK
  32. 0xFD3E, // ORNATE LEFT PARENTHESIS
  33. 0xFE35, // PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS
  34. 0xFE37, // PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET
  35. 0xFE39, // PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET
  36. 0xFE3B, // PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET
  37. 0xFE3D, // PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET
  38. 0xFE3F, // PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET
  39. 0xFE41, // PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET
  40. 0xFE43, // PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET
  41. 0xFE59, // SMALL LEFT PARENTHESIS
  42. 0xFE5B, // SMALL LEFT CURLY BRACKET
  43. 0xFE5D, // SMALL LEFT TORTOISE SHELL BRACKET
  44. 0xFF08, // FULLWIDTH LEFT PARENTHESIS
  45. 0xFF1C, // FULLWIDTH LESS-THAN SIGN
  46. 0xFF3B, // FULLWIDTH LEFT SQUARE BRACKET
  47. 0xFF5B, // FULLWIDTH LEFT CURLY BRACKET
  48. 0xFF62, // HALFWIDTH LEFT CORNER BRACKET
  49. 0xFFE9 // HALFWIDTH LEFTWARDS ARROW
  50. };
  51. const WCHAR awchNonBreakingAtLineStart[] = {
  52. 0x0029, // RIGHT PARENTHESIS
  53. 0x002D, // HYPHEN
  54. 0x005D, // RIGHT SQUARE BRACKET
  55. 0x007D, // RIGHT CURLY BRACKET
  56. 0x00AD, // OPTIONAL HYPHEN
  57. 0x00BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
  58. 0x02C7, // CARON
  59. 0x02C9, // MODIFIER LETTER MACRON
  60. 0x055D, // ARMENIAN COMMA
  61. 0x060C, // ARABIC COMMA
  62. 0x2013, // EN DASH
  63. 0x2014, // EM DASH
  64. 0x2016, // DOUBLE VERTICAL LINE
  65. 0x201D, // RIGHT DOUBLE QUOTATION MARK
  66. 0x2022, // BULLET
  67. 0x2025, // TWO DOT LEADER
  68. 0x2026, // HORIZONTAL ELLIPSIS
  69. 0x2027, // HYPHENATION POINT
  70. 0x203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
  71. 0x2046, // RIGHT SQUARE BRACKET WITH QUILL
  72. 0x207E, // SUPERSCRIPT RIGHT PARENTHESIS
  73. 0x208E, // SUBSCRIPT RIGHT PARENTHESIS
  74. 0x226B, // MUCH GREATER THAN
  75. 0x2574, // BOX DRAWINGS LIGHT LEFT
  76. 0x3001, // IDEOGRAPHIC COMMA
  77. 0x3002, // IDEOGRAPHIC FULL STOP
  78. 0x3003, // DITTO MARK
  79. 0x3005, // IDEOGRAPHIC ITERATION MARK
  80. 0x3009, // RIGHT ANGLE BRACKET
  81. 0x300B, // RIGHT DOUBLE ANGLE BRACKET
  82. 0x300D, // RIGHT CORNER BRACKET
  83. 0x300F, // RIGHT WHITE CORNER BRACKET
  84. 0x3011, // RIGHT BLACK LENTICULAR BRACKET
  85. 0x3015, // RIGHT TORTOISE SHELL BRACKET
  86. 0x3017, // RIGHT WHITE LENTICULAR BRACKET
  87. 0x3019, // RIGHT WHITE TORTOISE SHELL BRACKET
  88. 0x301B, // RIGHT WHITE SQUARE BRACKET
  89. 0x301E, // DOUBLE PRIME QUOTATION MARK
  90. 0x3041, // HIRAGANA LETTER SMALL A
  91. 0x3043, // HIRAGANA LETTER SMALL I
  92. 0x3045, // HIRAGANA LETTER SMALL U
  93. 0x3047, // HIRAGANA LETTER SMALL E
  94. 0x3049, // HIRAGANA LETTER SMALL O
  95. 0x3063, // HIRAGANA LETTER SMALL TU
  96. 0x3083, // HIRAGANA LETTER SMALL YA
  97. 0x3085, // HIRAGANA LETTER SMALL YU
  98. 0x3087, // HIRAGANA LETTER SMALL YO
  99. 0x308E, // HIRAGANA LETTER SMALL WA
  100. 0x309B, // KATAKANA-HIRAGANA VOICED SOUND MARK
  101. 0x309C, // KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK
  102. 0x309D, // HIRAGANA ITERATION MARK
  103. 0x309E, // HIRAGANA VOICED ITERATION MARK
  104. 0x30A1, // KATAKANA LETTER SMALL A
  105. 0x30A3, // KATAKANA LETTER SMALL I
  106. 0x30A5, // KATAKANA LETTER SMALL U
  107. 0x30A7, // KATAKANA LETTER SMALL E
  108. 0x30A9, // KATAKANA LETTER SMALL O
  109. 0x30C3, // KATAKANA LETTER SMALL TU
  110. 0x30E3, // KATAKANA LETTER SMALL YA
  111. 0x30E5, // KATAKANA LETTER SMALL YU
  112. 0x30E7, // KATAKANA LETTER SMALL YO
  113. 0x30EE, // KATAKANA LETTER SMALL WA
  114. 0x30F5, // KATAKANA LETTER SMALL KA
  115. 0x30F6, // KATAKANA LETTER SMALL KE
  116. 0x30FC, // KATAKANA-HIRAGANA PROLONGED SOUND MARK
  117. 0x30FD, // KATAKANA ITERATION MARK
  118. 0x30FE, // KATAKANA VOICED ITERATION MARK
  119. 0xFD3F, // ORNATE RIGHT PARENTHESIS
  120. 0xFE30, // VERTICAL TWO DOT LEADER
  121. 0xFE31, // VERTICAL EM DASH
  122. 0xFE33, // VERTICAL LOW LINE
  123. 0xFE34, // VERTICAL WAVY LOW LINE
  124. 0xFE36, // PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS
  125. 0xFE38, // PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET
  126. 0xFE3A, // PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET
  127. 0xFE3C, // PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET
  128. 0xFE3E, // PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET
  129. 0xFE40, // PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET
  130. 0xFE42, // PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET
  131. 0xFE44, // PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET
  132. 0xFE4F, // WAVY LOW LINE
  133. 0xFE50, // SMALL COMMA
  134. 0xFE51, // SMALL IDEOGRAPHIC COMMA
  135. 0xFE5A, // SMALL RIGHT PARENTHESIS
  136. 0xFE5C, // SMALL RIGHT CURLY BRACKET
  137. 0xFE5E, // SMALL RIGHT TORTOISE SHELL BRACKET
  138. 0xFF09, // FULLWIDTH RIGHT PARENTHESIS
  139. 0xFF0C, // FULLWIDTH COMMA
  140. 0xFF0E, // FULLWIDTH FULL STOP
  141. 0xFF1E, // FULLWIDTH GREATER-THAN SIGN
  142. 0xFF3D, // FULLWIDTH RIGHT SQUARE BRACKET
  143. 0xFF40, // FULLWIDTH GRAVE ACCENT
  144. 0xFF5C, // FULLWIDTH VERTICAL LINE
  145. 0xFF5D, // FULLWIDTH RIGHT CURLY BRACKET
  146. 0xFF5E, // FULLWIDTH TILDE
  147. 0xFF61, // HALFWIDTH IDEOGRAPHIC FULL STOP
  148. 0xFF63, // HALFWIDTH RIGHT CORNER BRACKET
  149. 0xFF64, // HALFWIDTH IDEOGRAPHIC COMMA
  150. 0xFF67, // HALFWIDTH KATAKANA LETTER SMALL A
  151. 0xFF68, // HALFWIDTH KATAKANA LETTER SMALL I
  152. 0xFF69, // HALFWIDTH KATAKANA LETTER SMALL U
  153. 0xFF6A, // HALFWIDTH KATAKANA LETTER SMALL E
  154. 0xFF6B, // HALFWIDTH KATAKANA LETTER SMALL O
  155. 0xFF6C, // HALFWIDTH KATAKANA LETTER SMALL YA
  156. 0xFF6D, // HALFWIDTH KATAKANA LETTER SMALL YU
  157. 0xFF6E, // HALFWIDTH KATAKANA LETTER SMALL YO
  158. 0xFF6F, // HALFWIDTH KATAKANA LETTER SMALL TU
  159. 0xFF70, // HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK
  160. 0xFF9E, // HALFWIDTH KATAKANA VOICED SOUND MARK
  161. 0xFF9F, // HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
  162. 0xFFEB // HALFWIDTH RIGHTWARDS ARROW
  163. };
  164. const WCHAR awchRomanInterWordSpace[] = {
  165. 0x0009, // TAB
  166. 0x0020, // SPACE
  167. 0x2002, // EN SPACE
  168. 0x2003, // EM SPACE
  169. 0x2004, // THREE-PER-EM SPACE
  170. 0x2005, // FOUR-PER-EM SPACE
  171. 0x2006, // SIX-PER-EM SPACE
  172. 0x2007, // FIGURE SPACE
  173. 0x2008, // PUNCTUATION SPACE
  174. 0x2009, // THIN SPACE
  175. 0x200A, // HAIR SPACE
  176. 0x200B // ZERO WIDTH SPACE
  177. };
  178. BOOL ScanWChar(const WCHAR awch[], int nArraySize, WCHAR wch)
  179. {
  180. int iMin = 0;
  181. int iMax = nArraySize - 1;
  182. while (iMax - iMin >= 2)
  183. {
  184. int iTry = (iMax + iMin + 1) / 2;
  185. if (wch < awch[iTry])
  186. iMax = iTry;
  187. else if (wch > awch[iTry])
  188. iMin = iTry;
  189. else
  190. return TRUE;
  191. }
  192. return (wch == awch[iMin] || wch == awch[iMax]);
  193. }
  194. #ifdef MLLBCONS_DEBUG
  195. void TestTable(const WCHAR awch[], int nArraySize)
  196. {
  197. int nDummy;
  198. for (int i = 0; i < nArraySize - 1; i++)
  199. {
  200. if (awch[i] >= awch[i + 1])
  201. nDummy = 0;
  202. }
  203. int cFound = 0;
  204. for (int n = 0; n < 0x10000; n++)
  205. {
  206. if (ScanWChar(awch, nArraySize, n))
  207. {
  208. cFound++;
  209. for (i = 0; i < nArraySize; i++)
  210. {
  211. if (awch[i] == n)
  212. break;
  213. }
  214. ASSERT(i < nArraySize);
  215. }
  216. }
  217. ASSERT(cFound == nArraySize);
  218. }
  219. #endif
  220. /////////////////////////////////////////////////////////////////////////////
  221. // CMLLBCons
  222. STDMETHODIMP CMLLBCons::BreakLineML(IMLangString* pSrcMLStr, long lSrcPos, long lSrcLen, long cMinColumns, long cMaxColumns, long* plLineLen, long* plSkipLen)
  223. {
  224. #ifdef MLLBCONS_DEBUG
  225. TestTable(awchNonBreakingAtLineEnd, ARRAYSIZE(awchNonBreakingAtLineEnd));
  226. TestTable(awchNonBreakingAtLineStart, ARRAYSIZE(awchNonBreakingAtLineStart));
  227. TestTable(awchRomanInterWordSpace, ARRAYSIZE(awchRomanInterWordSpace));
  228. #endif
  229. ASSERT_THIS;
  230. ASSERT_READ_PTR(pSrcMLStr);
  231. ASSERT_WRITE_PTR_OR_NULL(plLineLen);
  232. ASSERT_WRITE_PTR_OR_NULL(plSkipLen);
  233. HRESULT hr;
  234. IMLangStringWStr* pMLStrWStr;
  235. long lStrLen;
  236. long lBreakPos = -1; // Break at default position(cMaxColumns)
  237. long lSkipLen = 0;
  238. long lPrevBreakPos = 0;
  239. long lPrevSkipLen = 0;
  240. if (SUCCEEDED(hr = pSrcMLStr->QueryInterface(IID_IMLangStringWStr, (void**)&pMLStrWStr)) &&
  241. SUCCEEDED(hr = pSrcMLStr->GetLength(&lStrLen)) &&
  242. SUCCEEDED(hr = ::RegularizePosLen(lStrLen, &lSrcPos, &lSrcLen)))
  243. {
  244. long cColumns = 0;
  245. #ifndef ASTRIMPL
  246. long lSrcPosTemp = lSrcPos;
  247. long lSrcLenTemp = lSrcLen;
  248. #endif
  249. long lCandPos = 0;
  250. struct {
  251. unsigned fDone : 1;
  252. unsigned fInSpaces : 1;
  253. unsigned fFEChar : 1;
  254. unsigned fInFEChar : 1;
  255. unsigned fBreakByEndOfLine : 1;
  256. unsigned fNonBreakNext : 1;
  257. unsigned fHaveCandPos : 1;
  258. unsigned fSlashR : 1;
  259. } Flags = {0, 0, 0, 0, 0, 0, 0, 0};
  260. #ifdef ASTRIMPL
  261. CCharType<CT_CTYPE3, 128> ct3;
  262. CMLStrWalkW StrWalk(pMLStrWStr, lSrcPos, lSrcLen);
  263. #else
  264. LCID locale;
  265. hr = pMLStrWStr->GetLocale(0, -1, &locale, NULL, NULL);
  266. CCharType<CT_CTYPE3, 128> ct3(locale);
  267. #endif
  268. #ifdef ASTRIMPL
  269. while (StrWalk.Lock(hr))
  270. {
  271. ct3.Flush();
  272. for (int iCh = 0; iCh < StrWalk.GetCCh(); iCh++)
  273. {
  274. const WCHAR wch = StrWalk.GetStr()[iCh];
  275. const WORD wCharType3 = ct3.GetCharType(pSrcMLStr, StrWalk.GetPos() + iCh, StrWalk.GetLen() - iCh, &hr);
  276. if (FAILED(hr))
  277. break;
  278. #else
  279. while (lSrcLenTemp > 0 && SUCCEEDED(hr))
  280. {
  281. WCHAR* pszBuf;
  282. long cchBuf;
  283. long lLockedLen;
  284. ct3.Flush();
  285. if (SUCCEEDED(hr = pMLStrWStr->LockWStr(lSrcPosTemp, lSrcLenTemp, MLSTR_READ, 0, &pszBuf, &cchBuf, &lLockedLen)))
  286. {
  287. for (int iCh = 0; iCh < cchBuf; iCh++)
  288. {
  289. const WCHAR wch = pszBuf[iCh];
  290. const WORD wCharType3 = ct3.GetCharType(pszBuf + iCh, cchBuf - iCh);
  291. #endif
  292. const int nWidth = (wCharType3 & C3_HALFWIDTH) ? 1 : 2;
  293. if (wch == L'\r' && !Flags.fSlashR)
  294. {
  295. Flags.fSlashR = TRUE;
  296. }
  297. else if (wch == L'\n' || Flags.fSlashR) // End of line
  298. {
  299. Flags.fDone = TRUE;
  300. Flags.fBreakByEndOfLine = TRUE;
  301. if (Flags.fInSpaces)
  302. {
  303. Flags.fHaveCandPos = FALSE;
  304. lBreakPos = lCandPos;
  305. lSkipLen++; // Skip spaces and line break character
  306. }
  307. else
  308. {
  309. #ifdef ASTRIMPL
  310. lBreakPos = StrWalk.GetPos() + iCh; // Break at right before the end of line
  311. #else
  312. lBreakPos = lSrcPosTemp + iCh; // Break at right before the end of line
  313. #endif
  314. if (Flags.fSlashR)
  315. lBreakPos--;
  316. lSkipLen = 1; // Skip line break character
  317. }
  318. if (wch == L'\n' && Flags.fSlashR)
  319. lSkipLen++;
  320. break;
  321. }
  322. else if (ScanWChar(awchRomanInterWordSpace, ARRAYSIZE(awchRomanInterWordSpace), wch)) // Spaces
  323. {
  324. if (!Flags.fInSpaces)
  325. {
  326. Flags.fHaveCandPos = TRUE;
  327. #ifdef ASTRIMPL
  328. lCandPos = StrWalk.GetPos() + iCh; // Break at right before the spaces
  329. #else
  330. lCandPos = lSrcPosTemp + iCh; // Break at right before the spaces
  331. #endif
  332. lSkipLen = 0;
  333. }
  334. Flags.fInSpaces = TRUE;
  335. lSkipLen++; // Skip continuous spaces after breaking
  336. }
  337. else // Other characters
  338. {
  339. Flags.fFEChar = ((wCharType3 & (C3_KATAKANA | C3_HIRAGANA | C3_FULLWIDTH | C3_IDEOGRAPH)) != 0);
  340. if ((Flags.fFEChar || Flags.fInFEChar) && !Flags.fNonBreakNext && !Flags.fInSpaces)
  341. {
  342. Flags.fHaveCandPos = TRUE;
  343. #ifdef ASTRIMPL
  344. lCandPos = StrWalk.GetPos() + iCh; // Break at right before or after the FE char
  345. #else
  346. lCandPos = lSrcPosTemp + iCh; // Break at right before or after the FE char
  347. #endif
  348. lSkipLen = 0;
  349. }
  350. Flags.fInFEChar = Flags.fFEChar;
  351. Flags.fInSpaces = FALSE;
  352. if (Flags.fHaveCandPos)
  353. {
  354. Flags.fHaveCandPos = FALSE;
  355. if (!ScanWChar(awchNonBreakingAtLineStart, ARRAYSIZE(awchNonBreakingAtLineStart), wch))
  356. lBreakPos = lCandPos;
  357. }
  358. if (cColumns + nWidth > cMaxColumns)
  359. {
  360. Flags.fDone = TRUE;
  361. if (Flags.fNonBreakNext && lPrevSkipLen)
  362. {
  363. lBreakPos = lPrevBreakPos;
  364. lSkipLen = lPrevSkipLen;
  365. }
  366. break;
  367. }
  368. Flags.fNonBreakNext = ScanWChar(awchNonBreakingAtLineEnd, ARRAYSIZE(awchNonBreakingAtLineEnd), wch);
  369. if (Flags.fNonBreakNext)
  370. {
  371. // Need to remember previous break postion in case the line been terminated by the max columns
  372. lPrevBreakPos = lBreakPos;
  373. lPrevSkipLen = lSkipLen;
  374. }
  375. }
  376. cColumns += nWidth;
  377. }
  378. #ifdef ASTRIMPL
  379. StrWalk.Unlock(hr);
  380. if (Flags.fDone && SUCCEEDED(hr))
  381. break;
  382. #else
  383. HRESULT hrTemp = pMLStrWStr->UnlockWStr(pszBuf, 0, NULL, NULL);
  384. if (FAILED(hrTemp) && SUCCEEDED(hr))
  385. hr = hrTemp;
  386. if (Flags.fDone && SUCCEEDED(hr))
  387. break;
  388. lSrcPosTemp += lLockedLen;
  389. lSrcLenTemp -= lLockedLen;
  390. }
  391. #endif
  392. }
  393. pMLStrWStr->Release();
  394. if (Flags.fHaveCandPos)
  395. lBreakPos = lCandPos;
  396. if (SUCCEEDED(hr) && !Flags.fBreakByEndOfLine && lBreakPos - lSrcPos < cMinColumns)
  397. {
  398. lBreakPos = min(lSrcLen, cMaxColumns) + lSrcPos; // Default breaking
  399. lSkipLen = 0;
  400. }
  401. if (SUCCEEDED(hr) && !Flags.fDone)
  402. {
  403. if (Flags.fInSpaces)
  404. {
  405. lBreakPos = lSrcLen - lSkipLen;
  406. }
  407. else
  408. {
  409. lBreakPos = lSrcLen;
  410. lSkipLen = 0;
  411. }
  412. if (Flags.fSlashR)
  413. {
  414. lBreakPos--;
  415. lSkipLen++;
  416. }
  417. }
  418. }
  419. if (SUCCEEDED(hr))
  420. {
  421. if (plLineLen)
  422. *plLineLen = lBreakPos - lSrcPos;
  423. if (plSkipLen)
  424. *plSkipLen = lSkipLen;
  425. }
  426. else
  427. {
  428. if (plLineLen)
  429. *plLineLen = 0;
  430. if (plSkipLen)
  431. *plSkipLen = 0;
  432. }
  433. return hr;
  434. }
  435. STDMETHODIMP CMLLBCons::BreakLineW(LCID locale, const WCHAR* pszSrc, long cchSrc, long lMaxColumns, long* pcchLine, long* pcchSkip)
  436. {
  437. ASSERT_THIS;
  438. ASSERT_READ_BLOCK(pszSrc, cchSrc);
  439. ASSERT_WRITE_PTR_OR_NULL(pcchLine);
  440. ASSERT_WRITE_PTR_OR_NULL(pcchSkip);
  441. HRESULT hr = S_OK;
  442. IMLangStringWStr* pMLStrW;
  443. if (SUCCEEDED(hr = PrepareMLStrClass()) &&
  444. SUCCEEDED(hr = m_pMLStrClass->CreateInstance(NULL, IID_IMLangStringWStr, (void**)&pMLStrW)))
  445. {
  446. CMLStrBufConstStackW StrBuf((LPWSTR)pszSrc, cchSrc);
  447. long lLineLen;
  448. long lSkipLen;
  449. hr = pMLStrW->SetStrBufW(0, -1, &StrBuf, NULL, NULL);
  450. if (SUCCEEDED(hr))
  451. hr = pMLStrW->SetLocale(0, -1, locale);
  452. if (SUCCEEDED(hr))
  453. hr = BreakLineML(pMLStrW, 0, -1, 0, lMaxColumns, (pcchLine || pcchSkip) ? &lLineLen : NULL, (pcchSkip) ? &lSkipLen : NULL);
  454. if (SUCCEEDED(hr) && pcchLine)
  455. hr = pMLStrW->GetWStr(0, lLineLen, NULL, 0, pcchLine, NULL);
  456. if (SUCCEEDED(hr) && pcchSkip)
  457. hr = pMLStrW->GetWStr(lLineLen, lSkipLen, NULL, 0, pcchSkip, NULL);
  458. pMLStrW->Release();
  459. }
  460. if (FAILED(hr))
  461. {
  462. if (pcchLine)
  463. *pcchLine = 0;
  464. if (pcchSkip)
  465. *pcchSkip = 0;
  466. }
  467. return hr;
  468. }
  469. STDMETHODIMP CMLLBCons::BreakLineA(LCID locale, UINT uCodePage, const CHAR* pszSrc, long cchSrc, long lMaxColumns, long* pcchLine, long* pcchSkip)
  470. {
  471. ASSERT_THIS;
  472. ASSERT_READ_BLOCK(pszSrc, cchSrc);
  473. ASSERT_WRITE_PTR_OR_NULL(pcchLine);
  474. ASSERT_WRITE_PTR_OR_NULL(pcchSkip);
  475. HRESULT hr = S_OK;
  476. IMLangStringAStr* pMLStrA;
  477. if (uCodePage == 50000)
  478. uCodePage = 1252;
  479. if (SUCCEEDED(hr = PrepareMLStrClass()) &&
  480. SUCCEEDED(hr = m_pMLStrClass->CreateInstance(NULL, IID_IMLangStringAStr, (void**)&pMLStrA)))
  481. {
  482. CMLStrBufConstStackA StrBuf((LPSTR)pszSrc, cchSrc);
  483. long lLineLen;
  484. long lSkipLen;
  485. hr = pMLStrA->SetStrBufA(0, -1, uCodePage, &StrBuf, NULL, NULL);
  486. if (SUCCEEDED(hr))
  487. hr = pMLStrA->SetLocale(0, -1, locale);
  488. if (SUCCEEDED(hr))
  489. hr = BreakLineML(pMLStrA, 0, -1, 0, lMaxColumns, (pcchLine || pcchSkip) ? &lLineLen : NULL, (pcchSkip) ? &lSkipLen : NULL);
  490. if (SUCCEEDED(hr) && pcchLine)
  491. hr = pMLStrA->GetAStr(0, lLineLen, uCodePage, NULL, NULL, 0, pcchLine, NULL);
  492. if (SUCCEEDED(hr) && pcchSkip)
  493. hr = pMLStrA->GetAStr(lLineLen, lSkipLen, uCodePage, NULL, NULL, 0, pcchSkip, NULL);
  494. pMLStrA->Release();
  495. }
  496. if (FAILED(hr))
  497. {
  498. if (pcchLine)
  499. *pcchLine = 0;
  500. if (pcchSkip)
  501. *pcchSkip = 0;
  502. }
  503. return hr;
  504. }