Last week my wife and I returned from a one week trip to Portugal. We had not been there in more than a decade. Some things have changed while other not. People continue to be very nice and helpful especially when you attempt to utter a few words in Portuguese.
We arrived in Lisbon and headed to the rental car office. In less than an hour from arrival we were heading south to the Algarve. We have watched a few YouTube videos by Rick Steves and had purchases one of his travel guides for Portugal. In more than one occasion Rick has mentioned that Salema is his favorite beach in the Algarve. By experience we now know why. It is a small town sitting on a relatively small bay with blue and green waters. The population is less than 300 people. My wife took a picture at a restaurant on the beach while the temperature was hitting 96 F and we were enjoying delicious fresh sea food and drinking Sagres beer. From our table we could hear people conversion and different languages. Our waiter was taking care of a few tables and was able to switch to the language spoken by the customers (English, French and German). We only spent two days and headed back to Lisbon.
We also spent some time sightseeing, eating and drinking in Lagos. The town is much larger than Salema and is full of tourist and boats.
It is incredible what the European Union has done for the highways in Portugal. A couple decades ago I would not have driven to the Algarve for such a short period of time. Today it is possible to make a one day trip from Lisbon to the Algarve.
I will cover our stay in Lisbon in the next post.
As I have mentioned, I am porting some C/C++ code from 32 to 54 bits. The code is just a reduced set of APIs for the storage server at work. The following C code illustrates the current calls:
SENCOR_EXPORT int __stdcall MD5Compare ( char *fileName, char *otherFileName, unsigned char digest[MD5_DIGEST_LEN], BOOL *identical ); SENCOR_EXPORT int __stdcall MD5DigestToString ( unsigned char digest[MD5_DIGEST_LEN], char md5[MD5_DIGEST_STRING_LEN] ); SENCOR_EXPORT int __stdcall MD5Init ( MD5_CTX *context ); SENCOR_EXPORT int __stdcall MD5Final ( unsigned char digest[MD5_DIGEST_LEN], MD5_CTX *context ); SENCOR_EXPORT int __stdcall MD5Print ( unsigned char digest[MD5_DIGEST_LEN] ); SENCOR_EXPORT int __stdcall MD5Update ( MD5_CTX *context, unsigned char *input, unsigned int inputLen );
The following code (still work in progress) illustrates the replacement code in C++ using the Boost library:
#include "pch.h" #include <iostream> #include <algorithm> #include <iterator> #include <boost/uuid/detail/md5.hpp> #include <boost/algorithm/hex.hpp> using boost::uuids::detail::md5; using namespace std; /* * */ int MD5Init ( md5 *hash ) { hash = new md5(); // **** inform the caller what went on **** return 0; } /* * */ int MD5Final ( md5 *hash ) { // **** inform the caller what went on **** return 0; } /* * */ int MD5Update ( md5 *hash, string str ) { hash->process_bytes(str.data(), str.size()); // **** inform the caller what went on **** return 0; } /* * */ int MD5Final ( md5 *hash, md5::digest_type *digest ) { hash->get_digest(*digest); // **** inform the caller what went on **** return 0; } /* * Convert MD5 digest to string. */ int MD5DigestToString ( const md5::digest_type &digest, string &digestStr ) { // **** **** digestStr = ""; // **** convert to char[] **** const auto charDigest = reinterpret_cast<const char *>(&digest); // **** convert char[] digest to string **** boost::algorithm::hex(charDigest, charDigest + sizeof(md5::digest_type), std::back_inserter(digestStr)); // ???? ???? cout << "MD5DigestToString <<< digestString ==>" << digestStr << "<==" << endl; // **** inform the caller what went on **** return 0; } /* * Basic test to verify MD5 operation. */ void basicTest() { // **** general purpose string **** string str; string digestStr = ""; // **** prompt for first string **** cout << "basicTest >>> str: "; // **** loop processing input **** while (getline(cin, str)) { // **** check if we are done **** if (str.compare(string("-1")) == 0) { break; } // **** display string **** cout << "basicTest <<< str ==>" << str << "<==\n"; // **** generate a MD5 digest **** md5 hash; md5::digest_type digest; hash.process_bytes(str.data(), str.size()); hash.get_digest(digest); // **** convert to string and display MD5 digest **** MD5DigestToString( digest, digestStr); cout << "basicTest <<< digestStr ==>" << digestStr << "<==\n"; // **** prompt for next string to process **** cout << "basicTest >>> str [-1 to exit]: "; } } /* * Test scaffolding. */ int main() { bool done; // done looping flag char buffer[BUFSIZ]; // general purpose buffer md5::digest_type digest; // MD5 digest int retVal, // returned by this function selection, // user selection status; // returned by function calls md5 hash; // MD5 hash string digestStr, // digest string str; // string // **** initialization **** retVal = 0; // hope all goes well digestStr = ""; // for starters done = false; // for starters selection = 1; // for starters memset((void *)buffer, (int)0x00, sizeof(buffer)); // **** welcome message **** cout << "**** MD5 using Boost C++ Libraries ****\n"; // **** loop testing functions **** do { // **** display menu **** printf("\n"); printf("1\tbasicTest()\n"); printf("\n"); printf("2\tMD5Init()\n"); printf("3\tMD5Update()\n"); printf("4\tMD5Final()\n"); printf("5\tMD5DigestToString()\n"); printf("\n"); printf("-1\tQUIT\n"); // **** prompt and get user selection **** printf("\n>>> selection [%d]: ", selection); fgets( buffer, BUFSIZ, stdin); buffer[strlen(buffer) - 1] = '\0'; if (buffer[0] != '\0') selection = atoi(buffer); // **** process user selection **** switch (selection) { case -1: done = true; break; case 1: basicTest(); break; case 2: status = MD5Init(&hash); break; case 3: str = "hello world"; status = MD5Update( &hash, str); break; case 4: status = MD5Final( &hash, &digest); break; case 5: status = MD5DigestToString( digest, digestStr); // ???? ???? cout << "main <<< digestStr =>" << digestStr << "<==\n"; break; default: printf("main <<< invalid selection: %d\n", selection); break; } } while (!done); // **** clean up **** done: // **** inform caller what went on **** return retVal; }
Following is a run of the test code:
C:\Users\John\Documents\Visual Studio 2017\Projects\testmd5\x64\Debug>testmd5 **** MD5 using Boost C++ Libraries **** 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT >>> selection [1]: 1 basicTest >>> str: hello world basicTest <<< str ==>hello world<== MD5DigestToString <<< digestString ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<== basicTest <<< digestStr ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<== basicTest >>> str [-1 to exit]: -1 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT >>> selection [1]: 2 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT >>> selection [2]: 3 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT >>> selection [3]: 4 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT >>> selection [4]: 5 MD5DigestToString <<< digestString ==>5EB63BBBE01EEED093CB22BB8F5ACDC3<== main <<< digestStr =>5EB63BBBE01EEED093CB22BB8F5ACDC3<== 1 basicTest() 2 MD5Init() 3 MD5Update() 4 MD5Final() 5 MD5DigestToString() -1 QUIT
The same string is used for both sets. I will make some changes to the code to be able to prompt and accept different string.
The next step is to run some tests and will integrate into the code being ported.
If you are interested, the MD5 code can be found in my GitHub repository.
If you have comments or questions regarding this or any other post in this blog, or if you would like me to help with any phase in the SDLC (Software Development Life Cycle) of a product or service, please do not hesitate and leave me a note below. Requests for help will remain private.
Keep on reading and experimenting. It is the best way to learn!
John
Follow me on Twitter: @john_canessa