Click here to Skip to main content
15,892,927 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I want to base64 encode and decode a file and show it on the output screen.
My input file is as follows:

In other words
MAC address: "XY-XX-XX-XX-XX-XX" "X" can be anything hexadecimal. The hexadecimal "Y", written in binary format, is Y: "kmnp", where "p" is the least significant bit;

        p=0 --> unicast; 
        p=1 --> multicast; 
        n=0 --> globally assigned MAC; 
        n=1 --> locally administered; 
So, actually MAC can be changed to any combination in which p=0 and n=1;

"Y" can be 2, 6, A or E.

So the possible MAC addresses in Windows 7 for wireless adapters:


My code is:
C++
#include <stdio.h>
#include <string.h>
#include <string>
#include <cmath>
#include <cassert>
#include <limits>
#include <stdexcept>
#include <cctype>
#include <iostream>

using std::cout;
using std::endl;

static const int CHARS= 57;	

static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static const char reverse_table[128] = {
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
   64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
   52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
   64,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
   64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
   41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64
};

std::string base64_encode(const ::std::string &bindata)
{
   using ::std::string;
   using ::std::numeric_limits;

   if (bindata.size() > (numeric_limits<string::size_type>::max() / 4u) * 3u) {
      throw ::std::length_error("Converting too large a string to base64.");
   }

   const ::std::size_t binlen = bindata.size();
   // Use = signs so the end is properly padded.
   string retval((((binlen + 2) / 3) * 4), '=');
   ::std::size_t outpos = 0;
   int bits_collected = 0;
   unsigned int accumulator = 0;
   const string::const_iterator binend = bindata.end();

   for (string::const_iterator i = bindata.begin(); i != binend; ++i) {
      accumulator = (accumulator << 8) | (*i & 0xffu);
      bits_collected += 8;
      while (bits_collected >= 6) {
         bits_collected -= 6;
         retval[outpos++] = b64_table[(accumulator >> bits_collected) & 0x3fu];
      }
   }
   if (bits_collected > 0) { // Any trailing bits that are missing.
      assert(bits_collected < 6);
      accumulator <<= 6 - bits_collected;
      retval[outpos++] = b64_table[accumulator & 0x3fu];
   }
   assert(outpos >= (retval.size() - 2));
   assert(outpos <= retval.size());
   return retval;
}

std::string base64_decode(const ::std::string &ascdata)
{
   using ::std::string;
   string retval;
   const string::const_iterator last = ascdata.end();
   int bits_collected = 0;
   unsigned int accumulator = 0;

   for (string::const_iterator i = ascdata.begin(); i != last; ++i) {
      const int c = *i;
      if (::std::isspace(c) || c == '=') {
         // Skip whitespace and padding. Be liberal in what you accept.
         continue;
      }
      if ((c > 127) || (c < 0) || (reverse_table[c] > 63)) {
         throw ::std::invalid_argument("This contains characters not legal in a base64 encoded string.");
      }
      accumulator = (accumulator << 6) | reverse_table[c];
      bits_collected += 6;
      if (bits_collected >= 8) {
         bits_collected -= 8;
         retval += (char)((accumulator >> bits_collected) & 0xffu);
      }
   }
   return retval;
}
struct upload_status 
{
  int lines_read;
};

char (*read_file())[CHARS]
{
	FILE* hFile=NULL;
	char (*fileBuf)[CHARS] =NULL;
	std::string fileName("Hello.txt");
	size_t fileSize,len(0);

	//opening the file
	hFile = fopen(fileName.c_str(),"rb");
	if (hFile == NULL)
		throw "File Does not exist.";

	//get file size
	fseek(hFile,0,SEEK_END);
	fileSize = ftell(hFile);
	fseek(hFile,0,SEEK_SET);

	//Checking file size
	if(fileSize > 1*1024)
	{}

	int no_of_rows = fileSize/54 + 1;
	fileBuf = new char[no_of_rows + 1][CHARS];	//Extra row for our special character to be used in conditional statements,here ""

	for (len=0 ; len < no_of_rows; ++len)
		fread(fileBuf[len],sizeof(char),54,hFile);

	strcpy(fileBuf[len],"");
	return fileBuf;
}

int main()
{
	char *data;
	char (*FEdata)[CHARS] = NULL;
	int len(1);
	struct upload_status upload_ctx;
	upload_ctx.lines_read = 0;
	std::string str,Estr("");
	FEdata = read_file();

	while (len)
	{
	  data = FEdata[upload_ctx.lines_read];
	  if(strcmp(data,"")) 
	  {
		size_t len = strlen(data);
		str = std::string(data);
		Estr += base64_encode(str);
		cout<<base64_encode(str);
		upload_ctx.lines_read++;
		continue;
	  }
	  len = 0;
	}
	cout<<"\n\n\n\n"<<base64_decode(Estr);
	return 0;
}

This code is working well in mingw compiler, but in visual c++ its showing extra long encoding and decoding(I mean it's working as it should.)
Any suggestion ??
Posted
Updated 25-Jan-14 5:26am
v3

What's the problem? The length of base64-encoded string? There is no strict one-to-one correspondence between original and encoded data, as the base64 format is somewhat free; it can be formatted in arbitrary manner, which may create some extra length. The round trip of original, encoded and then decoded data does the same result; this is all that matters. You can also encode data by one program, decode with another one and compare the results.

[EDIT #1]

Thank you for showing your code and data.

As I can see, only first, shorter base64 text is correct, which I found by testing it. I have only one suggestion I can thing of. You are using some generic integer types line int. They don't have one fixed size for all environment. One of the compilers could use one size, silently assuming that only this size will be used, another compiler used different size. Now, sometimes integer data overflows integer objects, say, if you add a bit to an unsigned integer of maximum value, it rolls over. And usually this is done in unchecked way.

In other words, the code is incorrect, but it "casually" produce correct result for one of the compiler. So, do the following experiment: find out the sizes of all of the generic integer types for "correct" compilers (they all are equally "incorrect", just use the one which produced the working algorithm). You can always use sizeof operator and see what are they. After you learn the sizes of all those types, replace them with the sizes of fixed size. Make sure the code still works. And when you achieve that, try to compile it by another compiler.

[EDIT #2]

You can use, for example, fixed-size integer type definitions provided in boost library: http://www.boost.org/doc/libs/1_38_0/libs/integer/index.html[^].

—SA
 
Share this answer
 
v4
Comments
ansh_kumar 25-Jan-14 2:36am    
See the following for the output from two compilers.
Sergey Alexandrovich Kryukov 25-Jan-14 2:44am    
I'm not sure you provided correct past of second base64. I tested both; short base64 worked out correctly, long code throws exception by my converter...
—SA
ansh_kumar 25-Jan-14 2:49am    
Can you suggest any improvement in the code???
Sergey Alexandrovich Kryukov 25-Jan-14 2:53am    
Hard to say, it would be too much work for a Quick Answer. Did you write it by yourself?
I have only one suggestion: the difference could be just the size... hold on...
—SA
Sergey Alexandrovich Kryukov 25-Jan-14 3:01am    
Please see my update to the answer, after [EDIT]. It really can help.
—SA
After a very long observation I found that visual c++ behaves in a very strange why when it comes to file pointers.

See what i get from executing the following code:

C++
#include <stdio.h>
#include <iostream>

using std::cout;
using std::endl;

int main()
{
	FILE* file;
	size_t fileSize;
	char* str;
	file = fopen("Hello.txt","rb");

	str = new char[54];
	fread(str,sizeof(char),53,file);
	cout<<str;
	return 0;
}
</iostream></stdio.h>


In mingw the output is :
In other words
MAC address: ôXY-XX-XX-XX-XX-XXö ôXö


But in visual c++ it is:
In other words
MAC address: ôXY-XX-XX-XX-XX-XXö ôXö ═²²²²½½½½½½½½ε■ε■ε■


Visual c++ is printing until it finds a NULL, it is not putting a NULL after reading. Which is not what we want.
So we have to put '\0' at the end every time we read from the file.
So update the for loop in the read_file() as follows:
C++
int no_of_rows = fileSize/54 + 1;
int read(0);
fileBuf = new char[no_of_rows + 1][CHARS];

for (len=0 ; len < no_of_rows; ++len)
{
    read = fread(fileBuf[len],sizeof(char),54,hFile);
    fileBuf[len][read] ='\0';
}

Now the code works the same in both visual c++ and mingw. :)
 
Share this answer
 
v5

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900