// BinHex.cpp: implementation of the CBinHex class. // ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "BinHex.h" #include "BstrDebug.h" // These characters are the legal digits, in order, that are // used in Base64 encoding // const WCHAR rgwchBase64[] = L"ABCDEFGHIJKLMNOPQ" L"RSTUVWXYZabcdefgh" L"ijklmnopqrstuvwxy" L"z0123456789!*"; const char rgwchBase64ASCII[] = "ABCDEFGHIJKLMNOPQ" "RSTUVWXYZabcdefgh" "ijklmnopqrstuvwxy" "z0123456789!*"; CBinHex::CBinHex() { unsigned char i; // // Initialize our decoding array // memset(m_decodeArray, BBAD, 256); for (i = 0; i < 64; i++) { WCHAR wch = rgwchBase64[i]; m_decodeArray[wch] = i; } } // This function takes IN a single-char buffer, and puts the binhex // output into a bstr -- in the bstr, it's ASCII string // // Function name : ToBase64 // Description : // Return type : HRESULT // Argument : LPVOID pv // Argument : ULONG cbSize // Argument : char prepend // Argument : BSTR* pbstr // HRESULT CBinHex::ToBase64ASCII(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr) // // Encode and return the bytes in base 64 // { UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i; HRESULT hr = S_OK; *pbstr = NULL; if (cb % 3) cbSafe = cb + 3 - (cb % 3); // For padding else cbSafe = cb; // cbSafe is now a multiple of 3 cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars cbNeeded = cchNeeded; if (prepend != 0) { if (ivecnpad != NULL) *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv else *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv } else *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded); if (*pbstr) { BYTE* pb = (BYTE*)pv; char* pch = (char*)*pbstr; int cchLine = 0; if (prepend != 0) { *pch++ = (char) prepend; if (ivecnpad != NULL) { for (i = 0; i < 9; i++) *pch++ = (char) ivecnpad[i]; } } // // Main encoding loop // while (cb >= 3) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F); BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03); BYTE b3 = ((pb[2]&0x3F)); *pch++ = rgwchBase64ASCII[b0]; *pch++ = rgwchBase64ASCII[b1]; *pch++ = rgwchBase64ASCII[b2]; *pch++ = rgwchBase64ASCII[b3]; pb += 3; cb -= 3; } if (cb==0) { // nothing to do } else if (cb==1) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | 0; *pch++ = rgwchBase64ASCII[b0]; *pch++ = rgwchBase64ASCII[b1]; *pch++ = '$'; *pch++ = '$'; } else if (cb==2) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F); BYTE b2 = ((pb[1]&0x0F)<<2) | 0; *pch++ = rgwchBase64ASCII[b0]; *pch++ = rgwchBase64ASCII[b1]; *pch++ = rgwchBase64ASCII[b2]; *pch++ = '$'; } } else hr = E_OUTOFMEMORY; GIVEAWAY_BSTR(*pbstr); return hr; } // This function takes IN a single-char buffer, and puts the binhex // output into a bstr, but using only ASCII chars // // Function name : ToBase64 // Description : // Return type : HRESULT // Argument : LPVOID pv // Argument : ULONG cbSize // Argument : char prepend // Argument : BSTR* pbstr // HRESULT CBinHex::ToBase64(LPVOID pv, UINT cbSize, char prepend, char ivecnpad[9], BSTR* pbstr) // // Encode and return the bytes in base 64 // { UINT cb = cbSize, cbSafe, cchNeeded, cbNeeded, i; HRESULT hr = S_OK; *pbstr = NULL; if (cb % 3) cbSafe = cb + 3 - (cb % 3); // For padding else cbSafe = cb; // cbSafe is now a multiple of 3 cchNeeded = (cbSafe*4/3); // 3 normal bytes --> 4 chars cbNeeded = cchNeeded * sizeof(WCHAR); if (prepend != 0) { if (ivecnpad != NULL) *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2+18); // ivec & kv else *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded+2); // just kv } else *pbstr = ALLOC_BSTR_BYTE_LEN(NULL, cbNeeded); if (*pbstr) { BYTE* pb = (BYTE*)pv; WCHAR* pch = *pbstr; int cchLine = 0; if (prepend != 0) { *pch++ = (WCHAR) prepend; if (ivecnpad != NULL) { for (i = 0; i < 9; i++) *pch++ = (WCHAR) ivecnpad[i]; } } // // Main encoding loop // while (cb >= 3) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F); BYTE b2 = ((pb[1]&0x0F)<<2) | ((pb[2]>>6) & 0x03); BYTE b3 = ((pb[2]&0x3F)); *pch++ = rgwchBase64[b0]; *pch++ = rgwchBase64[b1]; *pch++ = rgwchBase64[b2]; *pch++ = rgwchBase64[b3]; pb += 3; cb -= 3; } if (cb==0) { // nothing to do } else if (cb==1) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | 0; *pch++ = rgwchBase64[b0]; *pch++ = rgwchBase64[b1]; *pch++ = L'$'; *pch++ = L'$'; } else if (cb==2) { BYTE b0 = ((pb[0]>>2) & 0x3F); BYTE b1 = ((pb[0]&0x03)<<4) | ((pb[1]>>4) & 0x0F); BYTE b2 = ((pb[1]&0x0F)<<2) | 0; *pch++ = rgwchBase64[b0]; *pch++ = rgwchBase64[b1]; *pch++ = rgwchBase64[b2]; *pch++ = L'$'; } } else hr = E_OUTOFMEMORY; GIVEAWAY_BSTR(*pbstr); return hr; } HRESULT CBinHex::PartFromBase64(LPSTR lpStr, BYTE *output, ULONG *numOutBytes) { HRESULT hr = S_OK; if (!output) return E_INVALIDARG; // // Loop over the input buffer until we get numOutBytes in output // ULONG bCurrent = 0; // what we're in the process of filling up int cbitFilled = 0; // how many bits in it we've filled ULONG numOut = 0; BYTE* pb = (BYTE*) output; // current destination (not filled) for (CHAR* pch=lpStr; *pch && numOut < *numOutBytes; pch++) { CHAR ch = *pch; // // Have we reached the end? // if (ch=='$') break; // // How much is this character worth? // BYTE bDigit = m_decodeArray[ch]; if (bDigit==BBAD) { hr = E_INVALIDARG; break; } // // Add in its contribution // bCurrent <<= 6; bCurrent |= bDigit; cbitFilled += 6; // // If we've got enough, output a byte // if (cbitFilled >= 8) { ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits *pb++ = (BYTE)(b&0xFF); // store the byte away cbitFilled -= 8; numOut++; } } // for _ASSERT(numOut <= *numOutBytes); if (hr!=S_OK) { *numOutBytes = 0; } else { if (numOut < *numOutBytes) *numOutBytes = numOut; } return hr; } HRESULT CBinHex::PartFromWideBase64(LPWSTR bStr, BYTE *output, ULONG *numOutBytes) { HRESULT hr = S_OK; if (!output) return E_INVALIDARG; // // Loop over the input buffer until we get numOutBytes in output // ULONG bCurrent = 0; // what we're in the process of filling up int cbitFilled = 0; // how many bits in it we've filled ULONG numOut = 0; BYTE* pb = (BYTE*) output; // current destination (not filled) for (WCHAR* pwch=bStr; *pwch && numOut < *numOutBytes; pwch++) { WCHAR wch = *pwch; // // Have we reached the end? // if (wch==L'$') break; // // How much is this character worth? // if (wch > 255) { hr = E_INVALIDARG; break; } BYTE bDigit = m_decodeArray[wch]; if (bDigit==BBAD) { hr = E_INVALIDARG; break; } // // Add in its contribution // bCurrent <<= 6; bCurrent |= bDigit; cbitFilled += 6; // // If we've got enough, output a byte // if (cbitFilled >= 8) { ULONG b = (bCurrent >> (cbitFilled-8)); // get's top eight valid bits *pb++ = (BYTE)(b&0xFF); // store the byte away cbitFilled -= 8; numOut++; } } // for _ASSERT(numOut <= *numOutBytes); if (hr!=S_OK) { *numOutBytes = 0; } else if (numOut < *numOutBytes) { *numOutBytes = numOut; } return hr; }