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.

196 lines
5.5 KiB

  1. // --------------------------------------------------------------------------------
  2. // EncodeQP.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. //
  6. // Stolen from Athena's source base by JulianJ, January 21st, 1997
  7. //
  8. // --------------------------------------------------------------------------------
  9. #include "private.h"
  10. //
  11. // Porting macros so the code can be copied without changes
  12. //
  13. #define MIMEOLEAPI
  14. #define AssertSz ASSERT_MSG
  15. #define TrapError(hr) ((EVAL(SUCCEEDED(hr))), (hr))
  16. #define CCHMAX_ENCODE_BUFFER 4096
  17. #define CHECKHR(hrExp) \
  18. if (FAILED (hrExp)) { \
  19. ASSERT_MSG(SUCCEEDED(hr), "%x", (hr)); \
  20. goto exit; \
  21. } else
  22. // --------------------------------------------------------------------------------
  23. // QP Encoder
  24. // --------------------------------------------------------------------------------
  25. static char rgchHex[] = "0123456789ABCDEF";
  26. #define ENCODEQPBUF 4096
  27. #define CCHMAX_QPLINE 72
  28. // --------------------------------------------------------------------------------
  29. // MimeOleEncodeStreamQP
  30. // --------------------------------------------------------------------------------
  31. MIMEOLEAPI HRESULT MimeOleEncodeStreamQP(IStream *pstmIn, IStream *pstmOut)
  32. {
  33. // Locals
  34. HRESULT hr=S_OK;
  35. BOOL fSeenCR=FALSE,
  36. fEOLN=FALSE;
  37. CHAR szBuffer[CCHMAX_ENCODE_BUFFER];
  38. ULONG cbRead=0,
  39. cbCurr=1,
  40. cbAttLast=0,
  41. cbBffLast=0,
  42. cbBuffer=0;
  43. UCHAR chThis=0,
  44. chPrev=0,
  45. buf[ENCODEQPBUF];
  46. // check params
  47. if (NULL == pstmIn || NULL == pstmOut)
  48. return TrapError(E_INVALIDARG);
  49. // Read from pstmIn and encode into pstmOut
  50. while (1)
  51. {
  52. // Reads one buffer full from the attachment
  53. if (cbCurr >= cbRead)
  54. {
  55. // Moves buffer from the last white space to front
  56. cbCurr = 0;
  57. while (cbAttLast < cbRead)
  58. buf[cbCurr++] = buf[cbAttLast++];
  59. // RAID-33342 - Reset cbAttLast - buff[0] is now equal to cbAttLast !!!
  60. cbAttLast = 0;
  61. // Read into buf
  62. CHECKHR(hr = pstmIn->Read(buf+cbCurr, ENCODEQPBUF-cbCurr, &cbRead));
  63. // No more ?
  64. if (cbRead == 0)
  65. break;
  66. // Adjusts buffer length
  67. cbRead += cbCurr;
  68. }
  69. // Gets the next character
  70. chThis = buf[cbCurr++];
  71. // Tests for end of line
  72. if (chThis == '\n' && fSeenCR == TRUE)
  73. fEOLN = TRUE;
  74. // Tests for an isolated CR
  75. else if (fSeenCR == TRUE)
  76. {
  77. szBuffer[cbBuffer++] = '=';
  78. szBuffer[cbBuffer++] = '0';
  79. szBuffer[cbBuffer++] = 'D';
  80. chPrev = 0xFF;
  81. }
  82. // CR has been taken care of
  83. fSeenCR = FALSE;
  84. // Tests for trailing white space if end of line
  85. if (fEOLN == TRUE)
  86. {
  87. if (chPrev == ' ' || chPrev == '\t')
  88. {
  89. cbBuffer--;
  90. szBuffer[cbBuffer++] = '=';
  91. szBuffer[cbBuffer++] = rgchHex[chPrev >> 4];
  92. szBuffer[cbBuffer++] = rgchHex[chPrev & 0x0F];
  93. chPrev = 0xFF;
  94. cbAttLast = cbCurr;
  95. cbBffLast = cbBuffer;
  96. }
  97. }
  98. // Tests for a must quote character
  99. else if (((chThis < 32) && (chThis != '\r' && chThis != '\t')) || (chThis > 126 ) || (chThis == '='))
  100. {
  101. szBuffer[cbBuffer++] = '=';
  102. szBuffer[cbBuffer++] = rgchHex[chThis >> 4];
  103. szBuffer[cbBuffer++] = rgchHex[chThis & 0x0F];
  104. chPrev = 0xFF;
  105. }
  106. // Tests for possible end of line
  107. else if (chThis == '\r')
  108. {
  109. fSeenCR = TRUE;
  110. }
  111. // Other characters (includes ' ' and '\t')
  112. else
  113. {
  114. // Stuffs leading '.'
  115. if (chThis == '.' && cbBuffer == 0)
  116. szBuffer[cbBuffer++] = '.';
  117. szBuffer[cbBuffer++] = chThis;
  118. chPrev = chThis;
  119. // Tests for white space and saves location
  120. if (chThis == ' ' || chThis == '\t')
  121. {
  122. cbAttLast = cbCurr;
  123. cbBffLast = cbBuffer;
  124. }
  125. }
  126. // Tests for line break
  127. if (cbBuffer > 72 || fEOLN == TRUE || chThis == '\n')
  128. {
  129. // Backtracks to last whitespace
  130. if (cbBuffer > 72 && cbBffLast > 0)
  131. {
  132. // RAID-33342
  133. AssertSz(cbAttLast <= cbCurr, "Were about to eat some text.");
  134. cbCurr = cbAttLast;
  135. cbBuffer = cbBffLast;
  136. }
  137. else
  138. {
  139. cbAttLast = cbCurr;
  140. cbBffLast = cbBuffer;
  141. }
  142. // Adds soft line break, if necessary
  143. if (fEOLN == FALSE)
  144. szBuffer[cbBuffer++] = '=';
  145. // Ends line and writes to storage
  146. szBuffer[cbBuffer++] = '\r';
  147. szBuffer[cbBuffer++] = '\n';
  148. // Write the buffer
  149. CHECKHR(hr = pstmOut->Write(szBuffer, cbBuffer, NULL));
  150. // Resets counters
  151. fEOLN = FALSE;
  152. cbBuffer = 0;
  153. chPrev = 0xFF;
  154. cbBffLast = 0;
  155. }
  156. }
  157. // Writes last line to storage
  158. if (cbBuffer > 0)
  159. {
  160. // Write the line
  161. CHECKHR(hr = pstmOut->Write(szBuffer, cbBuffer, NULL));
  162. }
  163. exit:
  164. // Done
  165. return hr;
  166. }