I'm currently using fopen to write/read binary files. With small files all is fines. But in some cases, when "exactly" the content is > 16K the remainder of the file is invalid !!!
The code is simple, fopen ... fread/fwrite ... fflush ... fclose !
I have try with C++. But now I got a problem during the "read"
in BinaryDefaultRead it return -1 !!! But really don't know why !
I only write 4 bytes at a time !!!
It is under Win7 64 bits with MSVC 2008 compiler.
#include <fstream>
using namespace std;
size_t BinaryDefaultRead(ifstream& stream, void* buffer, unsigned int bufferSize)
{
//return fread(buffer, 1, (size_t) bufferSize, file);
stream.read((char*)buffer, bufferSize);
if (!stream)
return -1;
return bufferSize;
}
size_t BinaryDefaultWrite(ofstream& stream, const void* buffer, unsigned int bufferSize)
{
//return fwrite(buffer, 1, (size_t) bufferSize, file);
stream.write((char*)buffer, bufferSize);
if (!stream)
return -1;
return bufferSize;
}
// Read an unsigned integer from a stream in a machine endian independent manner (for portability).
size_t BinaryReadUINT(ifstream& stream, unsigned int* value)
{
unsigned char buf[4];
size_t result = BinaryDefaultRead(stream, (void *)buf, 4);
if (result < 0)
return result;
*value = ((unsigned int) buf[0]) |
(((unsigned int) buf[1]) << 8) |
(((unsigned int) buf[2]) << 16) |
(((unsigned int) buf[3]) << 24);
return result;
}
// Write an unsigned integer to a stream in a machine endian independent manner (for portability).
size_t BinaryWriteUINT(ofstream& stream, unsigned int aValue)
{
unsigned char buf[4];
buf[0] = aValue & 0x000000ff;
buf[1] = (aValue >> 8) & 0x000000ff;
buf[2] = (aValue >> 16) & 0x000000ff;
buf[3] = (aValue >> 24) & 0x000000ff;
return BinaryDefaultWrite(stream, (void*)buf, 4);
}
// Read a floating point value from a stream in a machine endian independent manner (for portability).
size_t BinaryReadFLOAT(ifstream& stream, float* value)
{
union {
float f;
unsigned int i;
} u;
size_t result = BinaryReadUINT(stream, &u.i);
if (result < 0)
return result;
*value = u.f;
return result;
}
// Write a floating point value to a stream in a machine endian independent manner (for portability).
size_t BinaryWriteFLOAT(ofstream& stream, float aValue)
{
union {
float f;
unsigned int i;
} u;
u.f = aValue;
return BinaryWriteUINT(stream, u.i);
}
size_t BinaryReadUINTArray(ifstream& stream, unsigned int* buffer, unsigned int count)
{
size_t result;
for(unsigned int i = 0; i < count; i++)
{
result = BinaryReadUINT(stream, buffer + i);
if (result < 0)
return result;
}
return result;
}
size_t BinaryWriteUINTArray(ofstream& stream, unsigned int* buffer, unsigned int count)
{
size_t result;
for(unsigned int i = 0; i < count; i++)
{
result = BinaryWriteUINT(stream, buffer[i]);
if (result < 0)
return result;
}
return result;
}
size_t BinaryReadFLOATArray(ifstream& stream, float* buffer, unsigned int count)
{
size_t result;
for(unsigned int i = 0; i < count; i++)
{
result = BinaryReadFLOAT(stream, buffer + i);
if (result < 0)
return result;
}
return result;
}
size_t BinaryWriteFLOATArray(ofstream& stream, float* buffer, unsigned int count)
{
size_t result;
for(unsigned int i = 0; i < count; i++)
{
result = BinaryWriteFLOAT(stream, buffer[i]);
if (result < 0)
return result;
}
return result;
}
fopen is only used to open a file stream, not to read or write. fread and fwrite are used to do that.
fwrite and fread don't ensure you to write all the elements you pass them: they return the number of elements written, which can be lesser than the number of elements you passed it.
Just check the returned value, and keep fwrite-ing until you write out all of your elements or until there's an error with the stream: use ferror to check for an error.
From fwrite manual:
fread() and fwrite() return the number of items successfully read or written (i.e., not the number of characters). If an error occurs, or the end-of-file is reached, the return value is a short item count (or zero).
fread() does not distinguish between end-of-file and error, and callers must use feof(3) and ferror(3) to determine which occurred.
Related
I'm trying to apply the u-law algorithm to a wav file file.wav, and then create a new file file2.wav.
file.wav has 16 bits/sample, and I want to obtain a file2.wav that has 8 bits/sample.
This is my code:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
using std::string;
using std::fstream;
typedef struct WAV_HEADER {
char RIFF[4];
unsigned long ChunkSize;
char WAVE[4];
char fmt[4];
unsigned long Subchunk1Size;
unsigned short AudioFormat;
unsigned short NumOfChan;
unsigned long SamplesPerSec;
unsigned long bytesPerSec;
unsigned short blockAlign;
unsigned short bitsPerSample;
char Subchunk2ID[4];
unsigned long Subchunk2Size;
} wav_hdr;
int headerSize = 0;
string path = "file.wav";
wav_hdr wavHeader;
FILE* openFile() {
const char* filePath;
FILE *wavFile;
headerSize = sizeof(wav_hdr);
filePath = path.c_str();
wavFile = fopen(filePath, "rb");
if (wavFile == NULL) {
printf("Error\n");
}
fread(&wavHeader, headerSize, 1, wavFile);
return wavFile;
}
int8_t MuLaw_Encode(int16_t number)
{
const uint16_t MULAW_MAX = 0x1FFF;
const uint16_t MULAW_BIAS = 33;
uint16_t mask = 0x1000;
uint8_t sign = 0;
uint8_t position = 12;
uint8_t lsb = 0;
if (number < 0)
{
number = -number;
sign = 0x80;
}
number += MULAW_BIAS;
if (number > MULAW_MAX)
{
number = MULAW_MAX;
}
for (; ((number & mask) != mask && position >= 5); mask >>= 1, position--)
;
lsb = (number >> (position - 4)) & 0x0f;
return (~(sign | ((position - 5) << 4) | lsb));
}
int fileSize(FILE *file) {
int fileSize = 0;
fseek(file, 0, SEEK_END);
fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
return fileSize;
}
double bitsPerSample() {
double bitsPerE;
bitsPerE = wavHeader.bitsPerSample;
return bitsPerE;
}
int main() {
FILE *wavFile;
wavFile = openFile();
FILE* fptr2;
fptr2 = fopen("file2.wav", "wb");
int samples_count = fileSize(wavFile) / bitsPerSample();
short int *value = new short int[samples_count];
for (int16_t i = 0; i < samples_count; i++)
{
fread(&value[i], samples_count, 1, wavFile);
cout << value[i] << " "; // the output is in the attached picture
MuLaw_Encode(value[i]);
}
fwrite(value, sizeof(char), samples_count, fptr2);
return 0;
}
I took the u-law algorithm from here (2.1. µ-Law Compression (Encoding) Algorithm)
Am I doing something wrong? Because I obtain a corrupt file.
No header is ever written to the result file, so the first part of the data would get interpreted as a header, and it would be wrong. You can see in the file that it does not start with RIFFþR�WAVEfmt or something sufficiently similar.
The data written to the result file is value, the original data read from the input file, not the µ-law encoded data (which is only cout'ed and not saved).
The loop that reads the samples reads some wrong samples, because the computation of samples_count puts the current position back at the start, where the header is.
I'm trying to read a file and put bytes in a byte buffer, but when i try to read exe or zip file not all bytes are loaded in the buffer. my function:
char* read_file_bytes(const string &name) {
FILE *img = fopen(name.c_str(), "rb");
fseek(img, 0, SEEK_END);
unsigned long filesize = ftell(img);
char *buffer = (char*)malloc(sizeof(char)*filesize);
rewind(img);
fread(buffer, sizeof(char), filesize, img);
return buffer;
}
the piece of code that check the buffer:
char* bytes = read_file_bytes(path);
for(int i = 0; i < strlen(bytes); i++)
cout << hex << (unsigned int)(bytes[i]);
strlen() is designed for text characters, not for binary bytes. It stops counting when it encounters a nul char (0x00), which binary data is likely to contain.
Your read_file_bytes() function knows how many bytes it reads in. You need to return that number to the caller, eg:
typedef unsigned char byte;
byte* read_file_bytes(const std::string &name, unsigned long &filesize)
{
filesize = 0;
FILE *img = fopen(name.c_str(), "rb");
if (!img)
return NULL;
if (fseek(img, 0, SEEK_END) != 0)
{
fclose(img);
return NULL;
}
long size = ftell(img);
if (size == -1L)
{
fclose(img);
return NULL;
}
byte *buffer = static_cast<byte*>(std::malloc(size));
if (!buffer)
{
fclose(img);
return NULL;
}
rewind(img);
if (fread(buffer, 1, size, img) < size)
{
free(buffer);
close(img);
return NULL;
}
fclose(img);
filesize = size;
return buffer;
}
unsigned long filesize;
byte* bytes = read_file_bytes(path, filesize);
for(unsigned long i = 0; i < filesize; ++i)
std::cout << std::hex << static_cast<unsigned int>(bytes[i]);
free(bytes);
Note that this approach is very C-ish and error prone. A more C++ approach would look like this instead:
using byte = unsigned char;
// or, use std::byte in C++17 and later...
std::vector<byte> read_file_bytes(const std::string &name)
{
std::ifstream img;
img.exceptions(std::ifstream::failbit | std::ifstream::badbit);
img.open(name.c_str(), std::ifstream::binary | std::ifstream::ate);
std::ifstream::pos_type size = img.tellg();
ifs.seekg(0, std::ios::beg);
// or, use std::filesystem::file_size() instead...
std::vector<byte> buffer(size);
img.read(buffer.data(), size);
return buffer;
}
std::vector<byte> bytes = read_file_bytes(path);
for(byte b : bytes)
std::cout << std::hex << static_cast<unsigned int>(b);
I'm trying to read a string from a file encrypt it with AES and then save it to other file. Later I need to read the new file, decrypt and save the output to a new file again. The problem is some strange character are appearing.
int Crypt::__aesEncrypt(const unsigned char *msg, size_t msgLen, unsigned char **encMsg) {
EVP_CIPHER_CTX *aesEncryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(aesEncryptCtx);
unsigned char *aesKey = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesIV = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesPass = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesSalt = (unsigned char*)malloc(8);
if(RAND_bytes(aesPass, AES_KEYLEN/8) == 0) {
return FAILURE;
}
if(RAND_bytes(aesSalt, 8) == 0) {
return FAILURE;
}
if(EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), aesSalt, aesPass, AES_KEYLEN/8, AES_ROUNDS, aesKey, aesIV) == 0) {
return FAILURE;
}
strncpy((char*)aesKey, (const char*)"B374A26A714904AAB374A26A714904AA", AES_KEYLEN/8);
strncpy((char*)aesIV, (const char*)"B374A26A714904AA", AES_KEYLEN/16);
size_t blockLen = 0;
size_t encMsgLen = 0;
*encMsg = (unsigned char*)malloc(msgLen + AES_BLOCK_SIZE);
if(encMsg == NULL) return FAILURE;
(*encMsg)[0] = '\0';
if(!EVP_EncryptInit_ex(aesEncryptCtx, EVP_aes_256_cbc(), NULL, aesKey, aesIV)) {
return FAILURE;
}
if(!EVP_EncryptUpdate(aesEncryptCtx, *encMsg, (int*)&blockLen, (unsigned char*)msg, msgLen)) {
return FAILURE;
}
encMsgLen += blockLen;
if(!EVP_EncryptFinal_ex(aesEncryptCtx, *encMsg + encMsgLen, (int*)&blockLen)) {
return FAILURE;
}
EVP_CIPHER_CTX_cleanup(aesEncryptCtx);
free(aesEncryptCtx);
free(aesKey);
free(aesIV);
return encMsgLen + blockLen;
}
int Crypt::__aesDecrypt(unsigned char *encMsg, size_t encMsgLen, char **decMsg) {
EVP_CIPHER_CTX *aesDecryptCtx = (EVP_CIPHER_CTX*)malloc(sizeof(EVP_CIPHER_CTX));
EVP_CIPHER_CTX_init(aesDecryptCtx);
unsigned char *aesKey;
unsigned char *aesIV;
aesKey = (unsigned char*)malloc(AES_KEYLEN/8);
aesIV = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesPass = (unsigned char*)malloc(AES_KEYLEN/8);
unsigned char *aesSalt = (unsigned char*)malloc(8);
if(RAND_bytes(aesPass, AES_KEYLEN/8) == 0) {
return FAILURE;
}
if(RAND_bytes(aesSalt, 8) == 0) {
return FAILURE;
}
if(EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha1(), aesSalt, aesPass, AES_KEYLEN/8, AES_ROUNDS, aesKey, aesIV) == 0) {
return FAILURE;
}
strncpy((char*)aesKey, (const char*)"B374A26A714904AAB374A26A714904AA", AES_KEYLEN/8);
strncpy((char*)aesIV, (const char*)"B374A26A714904AA", AES_KEYLEN/16);
size_t decLen = 0;
size_t blockLen = 0;
*decMsg = (char*)malloc(encMsgLen);
if(*decMsg == NULL) return FAILURE;
if(!EVP_DecryptInit_ex(aesDecryptCtx, EVP_aes_256_cbc(), NULL, aesKey, aesIV)) {
return FAILURE;
}
if(!EVP_DecryptUpdate(aesDecryptCtx, (unsigned char*)*decMsg, (int*)&blockLen, encMsg, (int)encMsgLen)) {
return FAILURE;
}
decLen += blockLen;
if(!EVP_DecryptFinal_ex(aesDecryptCtx, (unsigned char*)*decMsg + decLen, (int*)&blockLen)) {
return FAILURE;
}
decLen += blockLen;
(*decMsg)[decLen] = '\0';
EVP_CIPHER_CTX_cleanup(aesDecryptCtx);
return encMsgLen;
}
Encrypting:
unsigned char *encMsg = NULL;
int size = __aesEncrypt((const unsigned char*)decrypted_string.c_str(), decrypted_string.size(), &encMsg);
return std::string(reinterpret_cast<const char*>(encMsg), size);
Decrypting:
char *decMsg = NULL;
int size = __aesDecrypt((unsigned char*)encrypted_string.c_str(), encrypted_string.size(), &decMsg);
return std::string(reinterpret_cast<const char*>(decMsg), size);
I can successfully crypt and decrypt, but some strange characters are appearing at the end of the encrypted file, they are like empty spaces:
AES is a block cypher. It takes blocks of 16 bytes, and encrypt them into a block of 16 byets. If you try to use it with data whose length is not a multiple of 16, padding (usually random data) is added to round it up to a multiple of 16 bytes. You need to manage the length of the data yourself.
Example:
int encryptHelper(const string& msg, ...)
{
uint32_t msgSize = msg.length();
newMsg.push_back((msgSize >> 0) & 0xFF);
newMsg.push_back((msgSize >> 8) & 0xFF);
newMsg.push_back((msgSize >> 16) & 0xFF);
newMsg.push_back((msgSize >> 24) & 0xFF);
string newMsg(reinterpret_cast<const char*>(&msgSize), sizeof(msgSize));
newMsg += msg;
return __aesEncrypt(newMsg.c_str(), newMsg.length(), ...);
}
int decryptHelper(const string& encrypted, ...)
{
string msg = ... whatever you are doing to decrypt
uint32_t actualSize = 0;
// remove signal first, then widen
actualSize |= static_cast<uint32_t>(static_cast<unsigned char>(msg[0])) << 0;
actualSize |= static_cast<uint32_t>(static_cast<unsigned char>(msg[1])) << 8;
actualSize |= static_cast<uint32_t>(static_cast<unsigned char>(msg[2])) << 16;
actualSize |= static_cast<uint32_t>(static_cast<unsigned char>(msg[3])) << 24;
string actualMsg = msg.substr(4, actualSize);
...
}
I didn't bother to write the exact code to call your functions because all that casting and memory leaking gave me nausea. Fill in the blanks.
Can somebody find the compression algorithm for this decompression code. Algorithms are not my forte and my friend who made the code didn't put comments in and somehow lost the compression code before leaving. Haa.
static inline unsigned char getbit_le(unsigned char byte, unsigned int pos)
{
return !!(byte & (1 << pos));
}
static inline unsigned char getbyte_le(unsigned char byte)
{
return byte;
}
static int lzss_decompress(BYTE *uncompr, DWORD uncomprLen,
BYTE *compr, DWORD comprLen)
{
unsigned int act_uncomprlen = 0;
unsigned int curbyte = 0;
unsigned int nCurWindowByte = 0xfee;
unsigned char window[4096];
unsigned int win_size = 4096;
memset(window, 0, win_size);
while (1) {
unsigned char bitmap;
if (curbyte >= comprLen)
break;
bitmap = getbyte_le(compr[curbyte++]);
for (unsigned int curbit_bitmap = 0; curbit_bitmap < 8; curbit_bitmap++) {
if (getbit_le(bitmap, curbit_bitmap)) {
unsigned char data;
if (curbyte >= comprLen)
goto out;
if (act_uncomprlen >= uncomprLen)
goto out;
data = ~getbyte_le(compr[curbyte++]);
uncompr[act_uncomprlen++] = data;
window[nCurWindowByte++] = data;
nCurWindowByte &= win_size - 1;
} else {
unsigned int copy_bytes, win_offset;
if (curbyte >= comprLen)
goto out;
win_offset = getbyte_le(compr[curbyte++]);
if (curbyte >= comprLen)
goto out;
copy_bytes = getbyte_le(compr[curbyte++]);
win_offset |= (copy_bytes >> 4) << 8;
copy_bytes &= 0x0f;
copy_bytes += 3;
for (unsigned int i = 0; i < copy_bytes; i++) {
unsigned char data;
if (act_uncomprlen >= uncomprLen)
goto out;
data = window[(win_offset + i) & (win_size - 1)];
uncompr[act_uncomprlen++] = data;
window[nCurWindowByte++] = data;
nCurWindowByte &= win_size - 1;
}
}
}
}
out:
return act_uncomprlen;
}
i have a class named IBuffer that uses std::vector as a storage of unsigned char data.
this class is part of my foundation library named core.lib.
responsibility of this class is writing data into buffer and reading from it.
ok
now i am using this class in another library for the purpose of serializing and deserializing messages received from network.
i am allways have problem with memory access violation reading location 0Xxxxxxx when i try to pushback new data in to std::vector.
as it is hard to write thousand lines of code here i put stack trace here i hope anyone help me to solve this problem.
ntdll.dll!#RtlpLowFragHeapFree#8() + 0x2c bytes
ntdll.dll!_RtlFreeHeap#12() + 0x7e bytes
kernel32.dll!_HeapFree#12() + 0x14 bytes
msvcr100d.dll!__free_base() + 0x29 bytes
msvcr100d.dll!__free_dbg_nolock() + 0x4ae bytes
msvcr100d.dll!__free_dbg() + 0x50 bytes
msvcr100d.dll!operator delete() + 0xb9 bytes
> ICore.dll!std::allocator<unsigned char>::deallocate(unsigned char * _Ptr=0x002c7810, unsigned int __formal=1) Line 182 + 0x9 bytes C++
ICore.dll!std::vector<unsigned char,std::allocator<unsigned char> >::_Insert_n(std::_Vector_const_iterator<std::_Vector_val<unsigned char,std::allocator<unsigned char> > > _Where=221 'Ý', unsigned int _Count=2, const unsigned char & _Val='') Line 1375 C++
ICore.dll!std::vector<unsigned char,std::allocator<unsigned char> >::insert(std::_Vector_const_iterator<std::_Vector_val<unsigned char,std::allocator<unsigned char> > > _Where=221 'Ý', unsigned int _Count=1, const unsigned char & _Val='') Line 1060 C++
ICore.dll!Utils::IBuffer::WriteShort(unsigned short data=256) Line 63 + 0x56 bytes C++
ICore.dll!Serialization::IBufferWriter::writeUShort(unsigned short data=256) Line 82 C++
IRNet.dll!IRNetwork::IStunMessage::AcceptWriter(Serialization::IIWriter * writer=0x0040f080) Line 340 + 0x2e bytes C++
IRNet.dll!Serialization::IBufferWriter::WriteObject<IRNetwork::IStunMessage>(const Object::IObject * object=0x002cb5f0) Line 105 + 0x17 bytes C++
IRNet.dll!IRNetwork::IStunMessage::Serialize(Object::SharedPtr<Utils::IBuffer> buffer={...}) Line 769 C++
IRNet.dll!IRNetwork::IStun::SendUnReliably(IRNetwork::IStunMessage * message=0x002cb5f0) Line 157 C++
IRNet.dll!IRNetwork::IStun::SendBind() Line 61 + 0xc bytes C++
IRNet.dll!IRNetwork::IStun::Bind(unsigned int localfd=184) Line 48 C++
IRNet.dll!IRNetwork::INatContext::StunBind(unsigned int fd=184) Line 52 + 0xc bytes C++
testDhcpv4.exe!TestStunAttribute::Start() Line 48 + 0x24 bytes C++
testDhcpv4.exe!wmain(int argc=1, wchar_t * * argv=0x002c71d8) Line 69 C++
testDhcpv4.exe!__tmainCRTStartup() Line 552 + 0x19 bytes C
testDhcpv4.exe!wmainCRTStartup() Line 371 C
kernel32.dll!#BaseThreadInitThunk#12() + 0x12 bytes
ntdll.dll!___RtlUserThreadStart#8() + 0x27 bytes
ntdll.dll!__RtlUserThreadStart#8() + 0x1b bytes
IBUffer.h
#include "stdafx.h"
#include "ICoreConfig.h"
#include "ILMutex.hxx"
#include "ILock.hxx"
#include <vector>
using namespace IThreading;
using namespace std;
namespace Utils
{
/*
#ifdef EXP_STL
# define DECLSPECIFIER __declspec(dllexport)
# define EXPIMP_TEMPLATE
#else
# define DECLSPECIFIER __declspec(dllimport)
# define EXPIMP_TEMPLATE extern
#endif
EXPIMP_TEMPLATE template class DECLSPECIFIER std::vector<unsigned char>;*/
template class ICORE_API std::allocator<unsigned char>;
template class ICORE_API std::vector<unsigned char,std::allocator<unsigned char> >;
/// <summary>
///
/// </summary>
typedef enum
{
/*Begin Of Buffer*/
BOB = 0,
/*End Of Buffer*/
EOB = 1,
/*Unknown*/
UNK = 2
} BufferState_t;
class ICORE_API IBuffer
{
public:
IBuffer(void);
IBuffer(IBuffer* newbuff);
~IBuffer(void);
//Methods
int Write(const void* data,size_t size);
int Write(const void** data, size_t sz);
int Write(size_t position , const void* data,size_t sz);
int WriteShort(unsigned short data);
int WriteShort(uint32_t position,unsigned short data);
int WriteByte(unsigned char data);
int WriteUInt(unsigned int data);
int WriteUlong(unsigned long data);
//************************************
// Method: ReadByte
// FullName: BufferPool::ReadByte
// Access: public
// Returns: unsigned char
// Qualifier:
//Description: Read and return one byte of data by starting from begining of buffer
//************************************
unsigned char ReadByte();
unsigned short ReadShort();
unsigned int ReadUint32();
unsigned long ReadUlong();
unsigned char* Read(size_t sz);
/** Converts a 16-bit value from host to TCP/IP network byte order (big-endian).
* #param x The 16-bit (in host byte order) value to convert.
* #retval #a x in TCP/IP network byte order.
*/
unsigned short HostToNetworkByteOrder(unsigned short x);
/* Memory alignment hack */
//************************************
// Method: HostToNetworkByteOrder
// FullName: BufferPool::HostToNetworkByteOrder
// Access: public
// Returns: unsigned short
// Qualifier:
// Parameter: const void * px
// Description: This method used when we want to Pars existing buffer
//************************************
unsigned short HostToNetworkByteOrder(const void* px);
unsigned short NetworkToHostByteOrder(const unsigned short x);
/** Converts a 32-bit value from host to TCP/IP network byte order (big-endian).
* #param x The 32-bit (in host byte order) value to convert.
* #retval #a x in TCP/IP network byte order.
*/
unsigned long HostToNetworkByteOrder(unsigned long x);
/* Memory alignment hack */
//************************************
// Method: HostToNetworkByteOrderUL
// FullName: BufferPool::HostToNetworkByteOrderUL
// Access: public
// Returns: unsigned long
// Qualifier:
// Parameter: const void * px
// Description: this method used when we want to pars existing buffer
//************************************
unsigned long HostToNetworkByteOrderUL(const void* px);
//* parse unsigned int type to byte array as is
vector<unsigned char> Uint32ToByteArray(unsigned int x);
uint8_t* ToUInt8ptr();
unsigned long NetworkToHostByteOrder(const unsigned long x);
/* IBuffer operator =(const IBuffer &buf);*/
IBuffer& operator =(IBuffer &Rhs);
IBuffer& operator =(char* rhs);
operator char*();
operator void*();
operator uint8_t*();
//************************************
// Method: operator++
// FullName: BufferPool::operator++
// Access: public
// Returns: BufferPool
// Qualifier:
// Description: This method increment dataPtr
// read one byte , increment dataPtr by one
// read short , increment dataPtr by two
// read unsigned int increment dataPtr by 4
// note : each read function set currPosion in suitable way
// we do this because of continuous buffer reading
//************************************
void operator ++();
bool operator<(const IBuffer& buff)
{
return this->Size() < buff.Size() ? true : false;
}
bool operator==(const IBuffer& buff)
{
return this->buffer == buff.buffer;
}
//Properties
bool IsEmpty();
unsigned char* Value();
/** Indicates whether we are on a Big Endian host or not.<br>
* IMPORTANT: Before calling this function, you should initialize the network stack by using
* #ref tnet_startup().
* #retval #a true if the program is running on a Big Endian host and #a false otherwise.
*/
bool IsBigEndian();
inline unsigned char HI_Uint16(unsigned short x)
{
return (((x) >> 8) & 0xFF) ;
}
inline unsigned char LOW_Uint16(unsigned short x)
{
return ((x) & 0xFF);
}
size_t Size() const;
void SetPtr();
void CleanUp();
void Move(int32_t count);
private:
inline int GetPosition()
{
return currPosition;
}
int SetPosition(int newpos);
public:
static class _Convert
{
public:
static inline unsigned short ToUShort(const unsigned char* u8_ptr)
{
return (((unsigned short)(u8_ptr)[0]) | ((unsigned short)(u8_ptr)[1])<<8);
}
static inline unsigned int ToUint32(const unsigned char* u8_ptr)
{
return (((unsigned int)(u8_ptr)[3]) | ((unsigned int)(u8_ptr)[2])<<8 | ((unsigned int)(u8_ptr)[1])<<16 | ((unsigned int)(u8_ptr)[0])<<24);
}
static inline signed int ToInt32(const unsigned char* u8_ptr)
{
return (((signed int)(u8_ptr)[0]) | ((signed int)(u8_ptr)[1])<<8 | ((signed int)(u8_ptr)[2])<<16 | ((signed int)(u8_ptr)[3])<<24);
}
protected:
private:
} Convert;
static BufferState_t bstate;
Mutex mMutex;
private:
vector<unsigned char> buffer;
vector<unsigned char>::pointer dataPtr;
int currPosition;
bool ptrSet;
};
}
IBuffer.cpp
#include "StdAfx.h"
#include "IBufferPool.h"
#include <iostream>
namespace Utils
{
IBuffer::IBuffer(void)
: currPosition(0), ptrSet(false)
{
/*buffer.push_back('\0');*/
SetPtr();
}
IBuffer::IBuffer( IBuffer* newbuff )
:currPosition(0)
{
}
IBuffer::~IBuffer(void)
{
if (GetPosition() != 0)
{
dataPtr = buffer.data();
}
buffer.clear();
dataPtr = NULL;
SetPosition(0);
/*std::cout<<"Ibuffer Freed \n";*/
}
//************************************
// Method: WriteByte
// FullName: BufferPool::WriteByte
// Access: public
// Returns: int
// Qualifier:
// Parameter: unsigned char data
// Description: write data of type byte in to buffer
//************************************
int IBuffer::WriteByte(unsigned char data)
{
Lock lock(mMutex);
buffer.push_back(data);
SetPtr();
return 0;
}
//tested OK
int IBuffer::WriteShort(unsigned short data)
{
Lock lock(mMutex);
unsigned char temp;
//first we convert to network byte order
/*unsigned short tmpData = HostToNetworkByteOrder(data);*/
//lower byte
temp = LOW_Uint16(/*tmpData*/data);
//buffer.push_back(temp); /// Access violation
buffer.insert(buffer.end(),1,temp);
temp = HI_Uint16(/*tmpData*/data);
//buffer.push_back(temp); /// Access violation
buffer.insert(buffer.end(),1,temp);
SetPtr();
return 0;
}
int IBuffer::WriteShort( uint32_t position,unsigned short data )
{
Lock lock(mMutex);
vector<unsigned char>::pointer pt = buffer.data();
pt+=position;
*pt=LOW_Uint16(data);
pt++;
*pt=HI_Uint16(data);
SetPtr();
return 0;
}
int IBuffer::WriteUInt(unsigned int data)
{
Lock lock(mMutex);
//unsigned int and unsigned long both have 4 byte length except that unsigned long can accept floating point numbers
vector<unsigned char> vt = Uint32ToByteArray(data);
for each(const unsigned char &i in vt)
{
buffer.push_back(i);
}
SetPtr();
return 0;
}
int IBuffer::WriteUlong( unsigned long data )
{
Lock lock(mMutex);
return WriteUInt(data);
}
vector<unsigned char> IBuffer::Uint32ToByteArray(unsigned int x)
{
Lock lock(mMutex);
vector<unsigned char> arrayOfByte(4);
for (int i = 0; i < 4; i++)
arrayOfByte[3 - i] = (x >> (i * 8));
return arrayOfByte;
}
uint8_t* IBuffer::ToUInt8ptr()
{
Lock lock(mMutex);
uint8_t* u8arr = (uint8_t*)this->buffer.data();
size_t sz = this->buffer.size();
u8arr[sz] = '\0';
return u8arr;
}
bool IBuffer::IsEmpty()
{
if(!buffer.size())
return true;
return false;
}
unsigned char* IBuffer::Value()
{
if(!dataPtr)
{
dataPtr = buffer.data();
}
return dataPtr;
}
unsigned short IBuffer::HostToNetworkByteOrder(unsigned short x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned short)(x) & 0xff00) >> 8) |
(((unsigned short)(x) & 0x00ff) << 8));
}
}
unsigned short IBuffer::HostToNetworkByteOrder(const void* px)
{
Lock lock(mMutex);
unsigned short y = IBuffer::Convert.ToUShort((const unsigned char*)px);//IRV_TO_UINT16((const unsigned char*)px);
return HostToNetworkByteOrder(y);
}
unsigned long IBuffer::HostToNetworkByteOrder(unsigned long x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned int)(x) & 0xff000000) >> 24) | \
(((unsigned int)(x) & 0x00ff0000) >> 8) | \
(((unsigned int)(x) & 0x0000ff00) << 8) | \
(((unsigned int)(x) & 0x000000ff) << 24));
}
}
unsigned long IBuffer::HostToNetworkByteOrderUL(const void* px)
{
Lock lock(mMutex);
unsigned long y = IBuffer::Convert.ToUShort((const unsigned char*)px);
return HostToNetworkByteOrder(y);
}
unsigned long IBuffer::NetworkToHostByteOrder(const unsigned long x)
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned int)(x) & 0x000000ff) << 24) | \
(((unsigned int)(x) & 0x0000ff00) << 8) | \
(((unsigned int)(x) & 0x00ff0000) >> 8) | \
(((unsigned int)(x) & 0xff000000) >> 24));
}
}
unsigned short IBuffer::NetworkToHostByteOrder( const unsigned short x )
{
Lock lock(mMutex);
if(IsBigEndian()){
return x;
}
else{
return ((((unsigned short)(x) & 0x00ff) << 8) |
(((unsigned short)(x) & 0xff00) >> 8));
}
}
bool IBuffer::IsBigEndian(){
/* If LITTLE_ENDIAN or BIG_ENDIAN macros have been defined in config.h ==> use them
* otherwise ==> dyn retrieve the endianness
*/
short word = 0x4321;
#if LITTLE_ENDIAN
return false;
#elif BIG_ENDIAN
return true;
#else
return ((*(signed char *)&word) != 0x21);
#endif
}
/*
IBuffer IBuffer::operator=( const IBuffer &buf )
{
IBuffer bf;
bf.buffer = buf.buffer;
return bf;
}*/
IBuffer& IBuffer::operator=(IBuffer& Rhs)
{
if (this != &Rhs)
{
if (this->dataPtr && this->Size()>0 && this->GetPosition()>0)
{
delete this;
}
buffer=Rhs.buffer;
dataPtr = Rhs.dataPtr;
currPosition = Rhs.GetPosition();
}
return *this;
}
IBuffer& IBuffer::operator=( char* rhs )
{
Lock lock(mMutex);
if (this->buffer.size() != 0)
{
this->buffer.clear();
}
if (this->currPosition !=0)
{
this->currPosition = 0;
}
this->Write(rhs,strlen(rhs));
return * this;
}
//Move forward data pointer by one
void IBuffer::operator++()
{
dataPtr++;
SetPosition(1);
//dataPtr+=GetPosition();
}
//************************************
// Method: ReadByte
// FullName: BufferPool::ReadByte
// Access: public
// Returns: unsigned char
// Qualifier:
// Parameter:
// Description: read data of type byte and move forward data pointer
//************************************
unsigned char IBuffer::ReadByte()
{
Lock lock(mMutex);
unsigned char ret = (*(dataPtr));
dataPtr++;
SetPosition(1);
return ret;
}
unsigned short IBuffer::ReadShort()
{
Lock lock(mMutex);
unsigned short ret=/*HostToNetworkByteOrder((unsigned char*)(dataPtr))*/IBuffer::Convert.ToUShort((unsigned char*)(dataPtr));
dataPtr+=2;
SetPosition(2);
return ret;
}
unsigned int IBuffer::ReadUint32()
{
Lock lock(mMutex);
//I DON NOT KHNOW MUST CONVERT RECIEVED MESSAGE TO LITTLE ENDIAN OR NOT?
unsigned int ui=/*HostToNetworkByteOrderUL((unsigned char*)(dataPtr))*/Convert.ToUint32((unsigned char*)(dataPtr));
dataPtr+=4;
SetPosition(4);
return ui;
}
unsigned long IBuffer::ReadUlong()
{
Lock lock(mMutex);
return (unsigned long) ReadUint32();
}
unsigned char* IBuffer::Read(size_t sz)
{
Lock lock(mMutex);
//return a block of data
unsigned char* tmp = new unsigned char;
/*Lock lock(mMutex);*/
for (int i = 1;i<=sz;i++)
{
tmp[i-1] = *dataPtr++;
}
//dataPtr +=sz;
tmp[sz] = '\0';
SetPosition(sz);
return tmp;
}
IBuffer::operator char*()
{
Lock lock(mMutex);
char* ret = (char*)buffer.data();
ret[buffer.size()] = '\0';
return ret;
}
IBuffer::operator void*()
{
return (void*)buffer.data();
}
int IBuffer::Write(const void* data,size_t size )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
/*Lock lock(mMutex);*/
for (size_t i=0;i<size;i++)
{
buffer.push_back(*udata++);
}
SetPtr();
return 0;
}
int IBuffer::Write( const void** data, size_t sz )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
/*Lock lock(mMutex);*/
for (size_t i=0;i<sz;i++)
{
buffer.push_back(*udata++);
}
SetPtr();
return 0;
}
int IBuffer::Write( size_t position , const void* data,size_t sz )
{
Lock lock(mMutex);
unsigned char* udata = (unsigned char*)data;
vector<unsigned char>::pointer pt = buffer.data();
/*Lock lock(mMutex);*/
pt+=position;
for (size_t i=0;i<sz;i++)
{
*pt=(unsigned char)(*udata++);
pt++;
}
SetPtr();
return 0;
}
IBuffer::operator uint8_t*()
{
return (uint8_t*) buffer.data();
}
void IBuffer::CleanUp()
{
if (this->Size() > 0 && this->dataPtr)
{
this->buffer.clear();
this->SetPosition(0);
this->dataPtr = NULL;
}
}
void IBuffer::SetPtr()
{
if (!IsEmpty() /*&& !ptrSet*/)
{
dataPtr=buffer.data();
ptrSet=true;
bstate = BOB;
}
}
size_t IBuffer::Size() const
{
return buffer.size();
}
int IBuffer::SetPosition( int newpos )
{
//if before read function take placed then current position must be updated to new position
//our CURSOR move forward by newpos
if (currPosition == 0)
{
currPosition = newpos;
}
else
{
currPosition += newpos;
if (this->Size() == currPosition)
{
bstate = EOB;
}
}
return 0;
}
void IBuffer::Move( int32_t count )
{
SetPosition(count);
dataPtr+=count;
}
BufferState_t IBuffer::bstate(BOB);
these 2 classes are not final.i only test to see is it possible to use vector as a buffer in this way i select or not.i think it is not good idea.
Edit:
i change the implementation of Ibuffer by using HeapAlloc and
HeapRealloc but i got this exeption
Unhandled exception at 0x774a2913 (ntdll.dll) in testDhcpv4.exe: 0xC0000374: A heap has been corrupted.
please help me.
with best wishes
Too much code, but I spotted this
IBuffer::operator char*()
{
Lock lock(mMutex);
char* ret = (char*)buffer.data();
ret[buffer.size()] = '\0';
return ret;
}
That is undefined behaviour (writing beyond the end of an array).
Also a red flag is that you are trying to maintain a vector and a pointer to it's data simultaneously. Obviously modifying the vector (by push_back for instance) can invalidate the pointer. I didn't see anything that made me think you'd got this wrong but since there's no benefit in doing it this way (just use an integer and call vector::data() when you need it) you might as well get rid.
Exposing C++ standard library containers at library boundaries can be perilous and fragile.
The problem is that the library and its client are sharing a ill-defined binary interface in the storage layout of STL objects. STL - by design - does not abstract much of its innards. Doing so would seriously impact performance.
This can bite you when the library and its client (which, remember, share a common set of headers files) get compiled with different storage layouts.
Whilst this might change between compilers (or even compiler versions), the issue that really nasty gotcha is conditionally compiled code - and I suspect it's this that's causing your problem.
The STL implementation that ships with Visual Studio has traditionally enabled various forms of sanity checking - such as on iterator use - in debug builds which alter the storage layout of the compiled STL objects.
So, in summary, I suspect you have the client build as a debug release and the library in release mode (or vice versa).