C++ Binary Level I/O

Started by
16 comments, last by Zahlman 17 years, 2 months ago
I'm trying to read a file, break it down to bit level and then apply an encryption algorithm I've written but I'm not quite sure how to go about that. The encryption algorithm is already written, it accepts 64-bits of input to proceed with encryption so I should break down the file into segments, each 64bit in size, which shouldn't be a problem if I have the file in binary format. However I have no clue how to get a random file into binary format( individual 1's and 0's). c++ file streaming seems more concerned with the content of the file rather than the file itself. I want to break down any file to 1's & 0's regardless of file content or type. Any ideas how to go about that ?
Serious Game Project: Midnight ManhattanTeam Website | Game Website | Screenshots Gallery | Game OverviewPositions Needed: Animators/Rigger | Texture/enviroment Artist | Character Modeller Recruitment Topic(more info) | Apply form | Email Contact: info.at.blueprintgames.com
Advertisement
I was dabbling in some encryption stuff myself and had some problems reading in files properly (though my problem wasn't with getting the binary data). Anyway, take a look at these snippets. This does a simple reversible XOR encryption, but you can see how it uses std::transform() and file streams (in binary mode) to read/write binary data to the files I'm encrypting.

...typedef char Byte;typedef long KeyType;...#pragma once#include "Encryptor.h"#include <iostream>#include <algorithm>class XOREncryptor : public Encryptor{public:	XOREncryptor(KeyType Key): mKey(Key), mPass(0) {}	virtual ~XOREncryptor() {}	virtual Byte operator()(const Byte& b)	{		mPass %= sizeof(KeyType);		return b ^ reinterpret_cast<Byte*>(&mKey)[mPass++];	}	virtual bool encrypt(std::istream& In, std::ostream& Out)	{		if (!In)			return false;		if (!Out)			return false;		In.seekg(In.beg);		Out.seekp(Out.beg);		std::transform(std::istreambuf_iterator<Byte>(In), std::istreambuf_iterator<Byte>(), std::ostreambuf_iterator<Byte>(Out), *this);		return true;	}	virtual KeyType getKey() const	{		return mKey;	}private:	KeyType mKey; // Key.	unsigned short mPass; // Pass.};


#include <iostream>#include <fstream>#include <string>#include "XOREncryptor.h"using std::cout;using std::cin;using std::endl;using std::string;using std::ifstream;using std::ofstream;using std::fstream;using std::ios;int main(int NumArgs, char** Args){	string inFileName, outFileName;	KeyType key = 1;	cout << "Input: ";	cin >> inFileName;	cout << "Output: ";	cin >> outFileName;	cout << "Key: ";	cin >> key;	if (cin.fail())		key = 1;	Encryptor* e = new XOREncryptor(key);	fstream fin(inFileName.c_str(), ios::in | ios::out | ios::binary);	fstream fout(outFileName.c_str(), ios::in | ios::out | ios::binary);	e->encrypt(fin, fout);	delete e;	return 0;}


The main() function just runs a little driver program, but you can see how it opens the streams. You can see how XOREncryptor uses std::transform() to handle the data. Hope this helps. Cheers.

Edit: Sorry for any confusing variable names. I went back and changed 'em. Also, I open fin and fout for both reading and writing for testing purposed (so I could easily swap the outputs and inputs). An ifstream and ofstream would do fine as well, but I'm sure you knew that. :-)
I imagine you should just read the file as any normal file, but make sure it's in binary mode (ios::binary if you're using ifstream). Then each character you read in is just a byte of data that can be converted to an equivalent 8 bit binary value.

There might already be a function to convert a char into an 8bit binary string, but if not it shouldn't be too hard to write yourself using some bitwise operators. Then you could either save the string of '1's and '0's to another file, or plug the data straight into your encryption algorithm.
I still prefer this:

FILE *pFile = fopen("file.ext", "rb");

.
.
(use fread/fgetc/fseek/etc.)
.
.

fclose(pFile);



Very readable and easy to understand.
You should be using ifstream's read function, rather than the streaming operators, so as to bypass formatting. Also be sure to have opened the file using ios::binary.

C++ provides no mechanism to directly access bits of data. The usual procedure is to maintain an array or buffer of chars, using the bit-shifting operators to do your jiggerypokery.

Admiral
Ring3 Circus - Diary of a programmer, journal of a hacker.
It sounds like you want a long string of the *characters* '1' and '0'. You don't need that.

Your data *is* in binary format when you have a chunk of chars. There's no need to rewrite it to consist only of the ascii values for '0' and '1'.
A char is a byte is 8 bit.
If you need 64 bit of input data, you take 8 bytes. (or two ints)
If you gave it a text string containing 64 1's and 0's, that would be 512 byte of data.
Quote:Original post by Spoonbender
It sounds like you want a long string of the *characters* '1' and '0'. You don't need that.

Actually I kinda do, the algorithm was part of a college assignment so it was supposed to be written to print out its operation in ascii characters.

I think I got a clear picture of how to take the input now, but I'm still lost as to how to translate that into ascii "binary" characters now and how to translate it back for file output.

So the data is stored in binary format, but how can I access that and get 1's and 0's.
Serious Game Project: Midnight ManhattanTeam Website | Game Website | Screenshots Gallery | Game OverviewPositions Needed: Animators/Rigger | Texture/enviroment Artist | Character Modeller Recruitment Topic(more info) | Apply form | Email Contact: info.at.blueprintgames.com
You could AND each byte of data with different powers of two to test for the bits, but this could be slow (though I'm sure you don't need things to be all too efficient for an assignment).

...typedef char Byte;Byte inputByte = getNextInputByte();if (Byte & 1){    // Byte has a '1' in the first place.}else{    // Byte has a '0' in the first place.}...


Something like this, perhaps? (I'm not sure just using 1, 2, 4, 8, etc. will work; you may need to enter the hex codes, i.e., 0x01.)

Hope this helps. Someone correct me if I did something wrong. :-)
You have to do some bit twiddling, here's some quick and dirty code:

unsigned char data = 20;string binaryString = "";// loop through all eight bitsfor(int i = 0; i < 8; ++i){	// shift the bit to the left	unsigned char bit = (1 << (7 - i));	// add correct character to the string	if((bit & data) == bit)		binaryString += '1';	else		binaryString += '0';}


This uses the bitshift operator to change the value of the 'bit' variable each loop iteration. It then AND's this value with the 'data' variable, and depending on the result, adds a '1' or '0' to the output string. This converts your byte of character information ('data') into an 8 byte string of 1's and 0's. Also check this wikipedia page for some useful info.

Hope that was what you were looking for.
Yep, shifting the bit is a much better idea than hardcoding powers of two. ^_^

This topic is closed to new replies.

Advertisement