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.

538 lines
11 KiB

  1. /* mime64 */
  2. /* MIME base64 encoder/decoder by Karl Hahn [email protected] 3-Aug-94 */
  3. /* Modified into an API by [email protected] 8-Jan-96 */
  4. #include "priv.h"
  5. #include "mime64.h"
  6. #define INVALID_CHAR (ULONG)-2
  7. #define IGNORE_CHAR (ULONG)-1
  8. extern "C" void DllAddRef();
  9. extern "C" void DllRelease();
  10. class CRefDll
  11. {
  12. public:
  13. CRefDll() {DllAddRef();}
  14. ~CRefDll() {DllRelease();}
  15. } ;
  16. HRESULT CopyTo(IStream* pstmIn,
  17. /* [unique][in] */ IStream *pstm,
  18. /* [in] */ ULARGE_INTEGER cb,
  19. /* [out] */ ULARGE_INTEGER *pcbRead,
  20. /* [out] */ ULARGE_INTEGER *pcbWritten)
  21. {
  22. if (cb.HighPart != 0)
  23. return E_INVALIDARG;
  24. DWORD dwBytes = cb.LowPart;
  25. DWORD dwStep = dwBytes;
  26. if (dwStep >= 0x8000)
  27. dwStep = 0x8000;
  28. LPVOID pv = GlobalAlloc(GPTR, dwStep);
  29. if (!pv)
  30. return E_OUTOFMEMORY;
  31. DWORD dwTotRead = 0;
  32. DWORD dwTotWrite = 0;
  33. HRESULT hres = NOERROR;
  34. for (dwBytes; dwBytes!=0; )
  35. {
  36. DWORD dwThisRead = dwStep;
  37. if (dwThisRead > dwBytes)
  38. {
  39. dwThisRead = dwBytes;
  40. }
  41. if (NOERROR!=pstmIn->Read(pv, dwThisRead, &dwThisRead) || !dwThisRead)
  42. {
  43. // Must be the end of the file
  44. break;
  45. }
  46. dwTotRead += dwThisRead;
  47. DWORD dwWrite;
  48. hres = pstm->Write(pv, dwThisRead, &dwWrite);
  49. if (FAILED(hres))
  50. {
  51. break;
  52. }
  53. dwTotWrite += dwWrite;
  54. if (dwWrite != dwThisRead)
  55. {
  56. hres = E_UNEXPECTED;
  57. break;
  58. }
  59. dwBytes -= dwThisRead;
  60. }
  61. GlobalFree(pv);
  62. pv = NULL;
  63. if (pcbRead)
  64. {
  65. pcbRead->HighPart = 0;
  66. pcbRead->LowPart = dwTotRead;
  67. }
  68. if (pcbWritten)
  69. {
  70. pcbWritten->HighPart = 0;
  71. pcbWritten->LowPart = dwTotWrite;
  72. }
  73. return(hres);
  74. }
  75. #undef new // Hack! need to resolve this (edwardp)
  76. class CStreamMem : public IStream
  77. {
  78. private:
  79. CStreamMem(UINT cbSize) : m_cbSize(cbSize), m_cRef(1), m_cbPos(0) {}
  80. void* operator new(size_t cbClass, UINT cbSize)
  81. {
  82. return(::operator new(cbClass + cbSize - 1));
  83. }
  84. public:
  85. static CStreamMem *Construct(UINT cbSize)
  86. {
  87. return(new(cbSize) CStreamMem(cbSize));
  88. }
  89. LPVOID GetPtr() { return(m_vData); }
  90. void SetSize(UINT cbSize) { m_cbSize = cbSize; }
  91. // IUnknown
  92. virtual STDMETHODIMP QueryInterface(
  93. /* [in] */ REFIID riid,
  94. /* [out] */ void **ppvObject);
  95. virtual STDMETHODIMP_(ULONG) AddRef(void)
  96. { return(++m_cRef); }
  97. virtual STDMETHODIMP_(ULONG) Release(void);
  98. // IStream
  99. virtual STDMETHODIMP Read(
  100. /* [out] */ void *pv,
  101. /* [in] */ ULONG cb,
  102. /* [out] */ ULONG *pcbRead);
  103. virtual STDMETHODIMP Write(
  104. /* [size_is][in] */ const void *pv,
  105. /* [in] */ ULONG cb,
  106. /* [out] */ ULONG *pcbWritten)
  107. { return(E_NOTIMPL); }
  108. virtual STDMETHODIMP Seek(
  109. /* [in] */ LARGE_INTEGER dlibMove,
  110. /* [in] */ DWORD dwOrigin,
  111. /* [out] */ ULARGE_INTEGER *plibNewPosition);
  112. virtual STDMETHODIMP SetSize(
  113. /* [in] */ ULARGE_INTEGER libNewSize)
  114. { return(E_NOTIMPL); }
  115. virtual STDMETHODIMP CopyTo(
  116. /* [unique][in] */ IStream *pstm,
  117. /* [in] */ ULARGE_INTEGER cb,
  118. /* [out] */ ULARGE_INTEGER *pcbRead,
  119. /* [out] */ ULARGE_INTEGER *pcbWritten)
  120. { return (::CopyTo(this, pstm, cb, pcbRead, pcbWritten)); }
  121. virtual STDMETHODIMP Commit(
  122. /* [in] */ DWORD grfCommitFlags)
  123. { return(E_NOTIMPL); }
  124. virtual STDMETHODIMP Revert( void)
  125. { return(E_NOTIMPL); }
  126. virtual STDMETHODIMP LockRegion(
  127. /* [in] */ ULARGE_INTEGER libOffset,
  128. /* [in] */ ULARGE_INTEGER cb,
  129. /* [in] */ DWORD dwLockType)
  130. { return(E_NOTIMPL); }
  131. virtual STDMETHODIMP UnlockRegion(
  132. /* [in] */ ULARGE_INTEGER libOffset,
  133. /* [in] */ ULARGE_INTEGER cb,
  134. /* [in] */ DWORD dwLockType)
  135. { return(E_NOTIMPL); }
  136. virtual STDMETHODIMP Stat(
  137. /* [out] */ STATSTG *pstatstg,
  138. /* [in] */ DWORD grfStatFlag)
  139. { return(E_NOTIMPL); }
  140. virtual STDMETHODIMP Clone(
  141. /* [out] */ IStream **ppstm)
  142. { return(E_NOTIMPL); }
  143. private:
  144. CRefDll m_cRefDll;
  145. ULONG m_cRef;
  146. UINT m_cbSize;
  147. UINT m_cbPos;
  148. // Must be the last field in the class
  149. BYTE m_vData[1];
  150. } ;
  151. STDMETHODIMP CStreamMem::QueryInterface(
  152. /* [in] */ REFIID riid,
  153. /* [out] */ void **ppvObject)
  154. {
  155. if (riid==IID_IUnknown || riid==IID_IStream)
  156. {
  157. AddRef();
  158. *ppvObject = (LPVOID)(IStream*)this;
  159. return(NOERROR);
  160. }
  161. *ppvObject = NULL;
  162. return(E_NOINTERFACE);
  163. }
  164. STDMETHODIMP_(ULONG) CStreamMem::Release( void)
  165. {
  166. --m_cRef;
  167. if (!m_cRef)
  168. {
  169. delete this;
  170. return(0);
  171. }
  172. return(m_cRef);
  173. }
  174. // IStream
  175. STDMETHODIMP CStreamMem::Read(
  176. /* [out] */ void *pv,
  177. /* [in] */ ULONG cb,
  178. /* [out] */ ULONG *pcbRead)
  179. {
  180. if (pcbRead)
  181. {
  182. *pcbRead = 0;
  183. }
  184. if (m_cbPos >= m_cbSize)
  185. {
  186. return(S_FALSE);
  187. }
  188. ULONG cbRest = m_cbSize - m_cbPos;
  189. if (cb > cbRest)
  190. {
  191. cb = cbRest;
  192. }
  193. CopyMemory(pv, m_vData + m_cbPos, cb);
  194. m_cbPos += cb;
  195. if (pcbRead)
  196. {
  197. *pcbRead = cb;
  198. }
  199. return(S_OK);
  200. }
  201. STDMETHODIMP CStreamMem::Seek(
  202. /* [in] */ LARGE_INTEGER dlibMove,
  203. /* [in] */ DWORD dwOrigin,
  204. /* [out] */ ULARGE_INTEGER *plibNewPosition)
  205. {
  206. LONG lOffset = (LONG)dlibMove.LowPart;
  207. // Make sure we are only using 32 bits
  208. if (dlibMove.HighPart==0 && lOffset>=0)
  209. {
  210. }
  211. else if (dlibMove.HighPart==-1 && lOffset<0)
  212. {
  213. }
  214. else
  215. {
  216. return(E_INVALIDARG);
  217. }
  218. switch (dwOrigin)
  219. {
  220. case STREAM_SEEK_SET:
  221. break;
  222. case STREAM_SEEK_CUR:
  223. lOffset = (LONG)m_cbPos + lOffset;
  224. break;
  225. case STREAM_SEEK_END:
  226. lOffset = (LONG)m_cbSize + lOffset;
  227. break;
  228. default:
  229. return(E_INVALIDARG);
  230. }
  231. // Check the new offset is in range (NOTE: it is valid to seek past "end of file")
  232. if (lOffset < 0)
  233. {
  234. return(E_INVALIDARG);
  235. }
  236. // Store the new offset and return it
  237. m_cbPos = (ULONG)lOffset;
  238. if (plibNewPosition)
  239. {
  240. plibNewPosition->HighPart = 0;
  241. plibNewPosition->LowPart = m_cbPos;
  242. }
  243. return(S_OK);
  244. }
  245. ULONG _BinaryFromASCII2( unsigned char alpha )
  246. {
  247. switch (alpha)
  248. {
  249. case ' ':
  250. case '\t':
  251. case '\n':
  252. case '\r':
  253. return(IGNORE_CHAR);
  254. default:
  255. if ( (alpha >= 'A') && (alpha <= 'Z') )
  256. {
  257. return (int)(alpha - 'A');
  258. }
  259. else if ( (alpha >= 'a') && (alpha <= 'z') )
  260. {
  261. return 26 + (int)(alpha - 'a');
  262. }
  263. else if ( (alpha >= '0') && (alpha <= '9' ) )
  264. {
  265. return 52 + (int)(alpha - '0');
  266. }
  267. return(INVALID_CHAR);
  268. case '+':
  269. return 62;
  270. case '/':
  271. return 63;
  272. }
  273. }
  274. #if 0
  275. struct _BinASCIIData
  276. {
  277. BOOL m_bInited;
  278. ULONG m_anBinary[256];
  279. } g_cBinASCIIData = { FALSE } ;
  280. void _InitTables()
  281. {
  282. if (g_cBinASCIIData.m_bInited)
  283. {
  284. return;
  285. }
  286. for (int i=0; i<256; ++i)
  287. {
  288. // Note this is thread-safe, since we always set to the same value
  289. g_cBinASCIIData.m_anBinary[i] = _BinaryFromASCII2((unsigned char)i);
  290. }
  291. // Set after initing other values to make thread-safe
  292. g_cBinASCIIData.m_bInited = TRUE;
  293. }
  294. inline ULONG _BinaryFromASCII( unsigned char alpha )
  295. {
  296. return(g_cBinASCIIData.m_anBinary[alpha]);
  297. }
  298. HRESULT Mime64Decode(LPCMSTR pStrData, IStream **ppstm)
  299. {
  300. *ppstm = NULL;
  301. _InitTables();
  302. // Waste some bytes so I don't have to worry about overflow
  303. CStreamMem *pstm = CStreamMem::Construct((lstrlen(pStrData)*3)/4 + 2);
  304. if (!pstm)
  305. {
  306. return(E_OUTOFMEMORY);
  307. }
  308. LPBYTE pData = (LPBYTE)pstm->GetPtr();
  309. int cbData = 0;
  310. int shift = 0;
  311. unsigned long accum = 0;
  312. BOOL quit = FALSE;
  313. // This loop will ignore white space, but quit at any other invalid characters
  314. for ( ; ; ++pStrData)
  315. {
  316. unsigned long value = _BinaryFromASCII(*pStrData);
  317. if ( value < 64 )
  318. {
  319. accum <<= 6;
  320. shift += 6;
  321. accum |= value;
  322. if ( shift >= 8 )
  323. {
  324. shift -= 8;
  325. value = accum >> shift;
  326. pData[cbData++] = (BYTE)value & 0xFF;
  327. }
  328. }
  329. else if (IGNORE_CHAR == value)
  330. {
  331. continue;
  332. }
  333. else
  334. {
  335. break;
  336. }
  337. }
  338. pstm->SetSize(cbData);
  339. *ppstm = pstm;
  340. return(NOERROR);
  341. }
  342. #endif
  343. #define CHARS_PER_LINE 60
  344. class COutputChars
  345. {
  346. public:
  347. COutputChars(LPMSTR pStrData) : m_pStrData(pStrData), m_cbLine(0) {}
  348. void AddChar(MCHAR cAdd)
  349. {
  350. *m_pStrData++ = cAdd;
  351. if (++m_cbLine == CHARS_PER_LINE)
  352. {
  353. *m_pStrData++ = '\n';
  354. m_cbLine = 0;
  355. }
  356. }
  357. LPMSTR GetPtr() { return(m_pStrData); }
  358. private:
  359. LPMSTR m_pStrData;
  360. UINT m_cbLine;
  361. } ;
  362. HRESULT Mime64Encode(LPBYTE pData, UINT cbData, IStream **ppstm)
  363. {
  364. static char const alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  365. "0123456789+/";
  366. *ppstm = NULL;
  367. // Waste some bytes so I don't have to worry about overflow
  368. // The 81/80 is to add a '\n' at the end of every 80 characters
  369. CStreamMem *pstm = CStreamMem::Construct((((cbData*4)/3 + 4)
  370. *(CHARS_PER_LINE+1)/CHARS_PER_LINE+2)*sizeof(MCHAR));
  371. if (!pstm)
  372. {
  373. return(E_OUTOFMEMORY);
  374. }
  375. COutputChars cStrData((LPMSTR)pstm->GetPtr());
  376. LPMSTR pSaveData = cStrData.GetPtr();
  377. int shift = 0;
  378. int save_shift = 0;
  379. unsigned long accum = 0;
  380. int index = 0;
  381. unsigned char blivit;
  382. unsigned long value;
  383. BOOL quit = FALSE;
  384. while ( ( cbData ) || (shift != 0) )
  385. {
  386. if ( ( cbData ) && ( quit == FALSE ) )
  387. {
  388. blivit = *pData++;
  389. --cbData;
  390. }
  391. else
  392. {
  393. quit = TRUE;
  394. save_shift = shift;
  395. blivit = 0;
  396. }
  397. if ( (quit == FALSE) || (shift != 0) )
  398. {
  399. value = (unsigned long)blivit;
  400. accum <<= 8;
  401. shift += 8;
  402. accum |= value;
  403. } /* ENDIF */
  404. while ( shift >= 6 )
  405. {
  406. shift -= 6;
  407. value = (accum >> shift) & 0x3Fl;
  408. blivit = alphabet[value];
  409. cStrData.AddChar(blivit);
  410. if ( quit != FALSE )
  411. {
  412. shift = 0;
  413. }
  414. }
  415. }
  416. if ( save_shift == 2 )
  417. {
  418. cStrData.AddChar('=');
  419. cStrData.AddChar('=');
  420. }
  421. else if ( save_shift == 4 )
  422. {
  423. cStrData.AddChar('=');
  424. }
  425. cStrData.AddChar('\n');
  426. cStrData.AddChar('\0');
  427. pstm->SetSize((int)(cStrData.GetPtr()-pSaveData) * sizeof(MCHAR));
  428. *ppstm = pstm;
  429. return(NOERROR);
  430. }