I have spent all of yesterday and this morning trying to think of how to do this, and I am still stuck. I don't understand how I can take a std::vector<char> (bytes) and extract values from it by combining the bytes. I have read everything that people have posted but I just don't see how I could do it.

var comment = reader.ReadBytes(24);

I mean how could i go about doing that with 24 bytes (chars) in the vector and store it in a variable to be re-written to another std::vector<char> later?

char a,b,c,d; unsigned long foo = (a << 24) | (b<<16) | (c<<8) | (d<<0);

I was given this idea, but I don't understand it very well, i read up about bitwise operators and such, still a bit hazzy on it. Even if I could do it by using this method with something like this

std::vector<char> test;
int index = 0;
unsigned long foo = (test.at(index) << 24) | (test.at(index+1) << 16) | (test.at(index+2) << 8) | (test.at(index+3) << 0);

How would i later re-write it back out to a std::vector<char>? Especially if I have to do something with the 24 bytes up above thats going to get very long fast. I mean there must be something else I can be doing here that will make this work.....Write all the bytes to a file and re-read them into an ifstream? Out of ideas....

Recommended Answers

All 17 Replies

Are you interpreting the data in std::vector<char> as big-endian or little-endian? To reverse the process you an just shift right and use the bitwise and operator.

So just to get this straight, you have a std::vector<char> full of whole unsigned digits correct? And if the user wants to read say 4 bytes( an int ) then you want to develop an algorithm so that the function reads 4 bytes from the char-vector into a variable and then returns the variable. Is that right?

Yes, The entire piece of C# code that I am trying to work with is below and shows every example of what I need to do with it into C++. he cheats and uses a memory stream though. I need to be able to take the std::vector<char> and break it into variables, alter them if i need to, then re-write these variables into a new std::vector<char>. I am not sure what u mean by big-endian or little-endian. The std::vector<char> can be filled with full unsigned digits or just other clutter that needs to be replaced in. Here is the code :)

var reader = new BinaryReader(new MemoryStream(data, false)); // create variable        

    // testing patch version
    var version = reader.ReadUInt32();
    if (version != 0x4e302e32)
        return data;

    var framecount = reader.ReadUInt32();
    if (framecount != 1)
        return data;

    var comment = reader.ReadBytes(24);
    //var linesOffset =
	reader.ReadUInt32();
    var maskOffset = reader.ReadUInt32();
    var paletteOffset = reader.ReadUInt32();
    var properties = reader.ReadUInt32();

    var width = reader.ReadInt32();
    if (width != oldWidth)
        return data;

    var height = reader.ReadInt32();
    var centerX = reader.ReadInt32();
    var centerY = reader.ReadInt32();

    // if height - centerY doesnt equal oldHeight return data due to error
    if (height - centerY != oldHeight)
        return data;

    if (centerY != 0)
    {
        int higher = newHeight - oldHeight;
        centerY -= higher;
        newHeight = oldHeight = height;
    }

    uint newMaskSize = (uint) (newHeight*4);
    uint newLinesOffset = maskOffset + newMaskSize;
    uint newLinesSize = (uint) (newHeight*4);
    uint newLineDataStart = newLinesOffset + newLinesSize;

    var outStream = new MemoryStream();
    var writer = new BinaryWriter(outStream);
	std::ofstream writer(outstream, std::ios::out | std::ios::binary);

    // Added by Master_G for testing purposes
    // UserFeedback.Info(string.Format("Resizing image #{0} for {1}x{2} to {3}x{4}",
    //    id, oldWidth, oldHeight, newWidth, newHeight));

    // writing the information provided above

    writer.write(version);
    writer.write(framecount);
    writer.write(comment);
    writer.write(newLinesOffset);
    writer.write(maskOffset);
    writer.write(paletteOffset);
    writer.write(properties);
    writer.write(newWidth);
    writer.write(newHeight);
    writer.write(centerX);
    writer.write(centerY);

    //UserFeedback.Info(string.Format("Version: {0}, FrameCount: {1}, Comment: {2}, newLinesOffset: {3}",
    //    version, framecount, comment, newLinesOffset));
    //UserFeedback.Info(string.Format("MaskOffSet: {0}, PaletteOffset: {1}, Properties: {2}",
    //    maskOffset, paletteOffset, properties));
    //UserFeedback.Info(string.Format("NewWidth: {0}, NewHeight: {1}, CenterX {2}, CenterY {3}",
    //   newWidth, newHeight, centerX, centerY));

    var osp = outStream.Position;

    // read every line of pixels from file into orgLineMasks array
    var orgLineMasks = new UInt32[oldHeight];
    for (var inLine = 0; inLine < oldHeight; inLine++)
        orgLineMasks[inLine] = reader.ReadUInt32();

    // read every original line start of old height into array
    var orgLineStarts = new UInt32[oldHeight + 1];
    for (var inLine = 0; inLine < oldHeight; inLine++)
        orgLineStarts[inLine] = reader.ReadUInt32();
    orgLineStarts[oldHeight] = (uint) data.Length;

    // Subtract the next piece in orgLineStarts from the previous piece
    // and then store into a new variable called orgLines
    var orgLines = new List<byte[]>(oldHeight);
    for (var inLine = 0; inLine < oldHeight; inLine++)
    {
        var orgLineSize = orgLineStarts[inLine + 1] - orgLineStarts[inLine];
        orgLines.Add(reader.ReadBytes((int) orgLineSize));
    }

    // initialize new lists
    var newLineMasks = new UInt32[newHeight];
    var newLines = new List<byte[]>(newHeight);

    // difference in the lines from oldHeight compared to newHeight
    // e.g. 1200 - 1024 = 176
    int extraLines = newHeight - oldHeight;

    // determine whether shrinking resolution or expanding it
    int shrinking = extraLines < 0;
    int expanding = extraLines > 0; 

    // define middle of oldHeight
    // e.g. 1024/2 = 512
    int centreLine = oldHeight / 2;

    // e.g. 512 + 176 = 688
    int shrinkSkipStart = centreLine + extraLines;
    int shrinkSkipEnd = centreLine;

    // duplication is the amount of times every duplicated line, is duplicated
    // e.g. duplication = 1 + (176 + 1)/(1024/2)
    // e.g. duplication = 1.34570
    int duplication = 1 + (extraLines + 1)/(oldHeight/2);
    // the duplication block size is the block that is being duplicated
    // the last line of which MIGHT not be duplicated 'duplication' times
    //  eg if duplication is 2, extralines = 501, dbs = 251, the last of which is
    //  duped just once.
    int duplicationBlockSize = (extraLines + duplication - 1)/duplication;

    int dupStart = centreLine - duplicationBlockSize / 2;
    int dupEnd = dupStart + duplicationBlockSize;

    int dupedLines = 0; //'UNIT'TEST
    for (int inLine = 0; inLine < oldHeight; inLine++)
    {
        // If shrinking skip 'extralines' lines on the centerline and above
        if (shrinking && inLine >= shrinkSkipStart && inLine < shrinkSkipEnd)
        {
            dupedLines--;
            continue;
        }
        // newLineMasks has same ammount of positions as newHeight
        // e.g. 1200 => 1200
        // 
        newLineMasks[newLines.Count] = orgLineMasks[inLine];

        var newLine = StretchLine(orgLines[inLine], oldWidth, newWidth);
        newLines.Add(newLine);

        // If expanding, duplicate the right amount of lines before centreLine
        if (!expanding || inLine < dupStart || inLine >= dupEnd)
            continue;

        for (var rep = 0; rep < duplication && dupedLines < extraLines; rep++)
        {
            newLineMasks[newLines.Count] = orgLineMasks[inLine];
            newLines.Add(newLine);
            dupedLines++;
        }
    }

    var nextLineStart = newLineDataStart;

    foreach (var newLineMask in newLineMasks)
        writer.Write(newLineMask);

    osp = outStream.Position;

    foreach (var newLine in newLines)
    {
        writer.Write(nextLineStart);
        nextLineStart += (uint)newLine.Length;
    }

    osp = outStream.Position;

    foreach (var newLine in newLines)
        writer.Write(newLine);

    writer.Close();
            
    var newSlp = outStream.ToArray();

    return newSlp;

The thing is reading 24 bytes and putting it into a number is a hassle because C++ native data type on a 32 bit platform the biggest you will get is 8 bytes, from a double. If it was bits that you wanted to read then you can fit 64 bits into a double.

So If you can limit your self to just read upto 8 bytes then it wont be hard, in fact you can do something like this :

//simple conversion, note no error checking...
inline int toInt(char c){ 
	return c - '0'; 
}

//reads numOfBytes from data begining at the offset index in data
//if not enough bytes are available it returns what it can read
//prints a error message if an the size of the return type is less than the number
//of bytes requested or if the number of bytes requested is greater than the number of
template<typename T>
T readBytes(const std::vector<char>& data, size_t numOfBytes,  size_t offset = 0 ){
        assert(numOfBytes > 0 && <= 8);
	T result = T();
	//change to something more appropriate if needed, for example throw an exception or log error?
	if(sizeof(T) < numOfBytes) cout << "Warning overflow can occurr\n";
	if(data.size() < numOfBytes/4) cout << "Warning not enough data\n";

	if(numOfBytes == 1) result = toInt(data[0]);
	else if(numOfBytes == 2) result = (toInt(data[0]) << 8) | (toInt(data[1]) << 0);
	else if(numOfBytes == 3) result = (toInt(data[0]) << 16) | (toInt(data[1]) << 8) | (toInt(data[2]) << 0);
	//..more else if or you can use a For loop

	return result;
}

Another option and a good one is for you to use GNU MP BIGNUM LIBRARY. Its dedicated to handle large number in a fast time. So the option is your. BTW, why are you porting C# to C++?

Porting C# to C++ because the client this is supposed to be compatible for is in C++ and not C#.

Can u quickly explain the toInt? And i assume I continue this up until numOfBytes == 8?

And next, how would I do this in reverse, just change the << to >>?

For the toInt(char c), it has to do with the ascii value. Assume that the variable c
is = '9'. If we subtract '0' from '9', that is '9' - '0' = 9. We get the integer nine.
We want to do this because '9' != 9, that is '9' has a different ascii value.

To reverse it you would do something like this :

int main(){
	char c1 = 0x56;
	char c2 = 0x78;
	int combined = (c1 << 8) | (c2 << 0 ); //assume that sizeof(int) = 4 * sizeof(char) which is true for most
	cout << "Combined = " << showbase << hex << combined << endl;
	int highPart = (combined >>8) & c1;
	int lowPart =  combined & c2;
	cout << "HighPart = " << highPart << "\n" << "LowPart = " << lowPart << endl;
}

So if there were 4 pieces then it would be:

int main(){
	char c1 = 0x56;
	char c2 = 0x78;
        char c3 = 0x92;
        char c4 = 0xF0;
	int combined = ((c3 << 24)| (c2 << 16) | (c3 << 8) | (c4 << 0 )); //assume that sizeof(int) = 4 * sizeof(char) which is true for most
	cout << "Combined = " << showbase << hex << combined << endl;
	int highPart = (combined >>24) & c3; // ????????
        int middlePart = // ??????
	int lowPart =  combined & c2;
	cout << "HighPart = " << highPart << "\n" << "LowPart = " << lowPart << endl;
}

it would be :

int main(){
	char c1 = 0x12;
	char c2 = 0x34;
    char c3 = 0x56;
    char c4 = 0x78;
	//assume that sizeof(int) = 4 * sizeof(char) which is true for most
	int combined = ((c1 << 24)| (c2 << 16) | (c3 << 8) | (c4 << 0 )); 
	cout << "Combined = " << showbase << hex << combined << endl;

	int highPart = (combined >>24) & c1;
    int midC2 = (combined >> 16) & c2;
	int midC3 = (combined >> 8) & c3;
	int lowPart =  (combined >> 0) & c4;
	cout << highPart << " " << midC2 << " " << midC3 << " " << lowPart << endl;
}

It would be: (don't use firstPerson's code, its faulty.. sorry fP..)

int main(){
  unsigned char c1 = 0x56;
  unsigned char c2 = 0x78;
  unsigned char c3 = 0x92;
  unsigned char c4 = 0xF0;
  int combined = ((c1 << 24)| (c2 << 16) | (c3 << 8) | (c4 << 0)); //construct 32bit unsigned integer from 4 unsigned chars (i.e. bytes).
  cout << "Combined = " << showbase << hex << combined << endl;
  
  //now, to reconstruct the four bytes:
  unsigned int byte1 = (combined >> 24) & 0xFF;
  unsigned int byte2 = (combined >> 16) & 0xFF;
  unsigned int byte3 = (combined >> 8) & 0xFF;
  unsigned int byte4 = combined & 0xFF;
  cout << "Byte1 = " << showbase << hex << byte1 
       << "Byte2 = " << showbase << hex << byte2
       << "Byte3 = " << showbase << hex << byte3
       << "Byte4 = " << showbase << hex << byte4 << endl;
}

If you want to store a vector of bytes in a way that is closest to the type byte, you should store them as "unsigned char" not "char", you run in the danger of chars being interpreted as either ASCII characters or as signed integers (either one is not what you want, from looking at the C# code).

However, I must mention. Using a vector of chars (or unsigned chars) is far from being the easiest thing to do in this case. I would suggest that you look at stringstream and stringbuf from the C++ standard libraries. This is almost the exact equivalent to MemoryStream in C#. All you have to do is setup an array of chars (char*) filled with your data, then use the function stringstream::rdbuf() to get the stringbuf attached to your stringstream object, and use the function stringbuf::pubsetbuf() on that stringbuf to attach the stringstream to your array of chars. After that, you can interact with the stringstream object like you would with any iostream in C++ (like reading and writing to a file) almost exactly like the above C# code uses MemoryStream. That should make your task a heck of a lot easier than doing your own, possibly faulty, code for this.

commented: Very thorough explanation :) +0

is it faulty because the variable might get changed before the byte extraction?

Ok i will read up on it and post if i still need help :)

Ok, so I did some reading, and I really hate CPlusPlus.com, I never understand their website..... could u provide a short example on how you would use all those individual functions to connect the stringstream to the vector<char>? Ty :)

Well from a vector<char> is probably not the easiest thing. A vector of chars is not a good way of representing a buffer. You should use either a static or dynamic array or the stringbuf directly. Assuming a static array of chars, this little program shows quite simply how to use stringstream and linking it to a external buffer you have already:

#include <iostream>
#include <sstream> //include the header for the stringstream and stringbuf classes.

using namespace std;

int main() {
  char buf[42]; //say you have a static buffer of chars and you want to read and write to it.

  stringstream my_stream; //create a string stream that will be used as the buffer.

  my_stream.rdbuf()->pubsetbuf(buf, 42); //link the string stream to your static buffer.

  //now you can do any kind of binary or formatted reading and writing operations you like, via my_stream:

  streampos starting_pos = my_stream.tellp(); //recording the start position is always useful. 

  my_stream.write("Start here!", 12); //writes a null-terminated string to the stream.

  unsigned int value = 34;
  my_stream.write(reinterpret_cast<char*>(&value),sizeof(unsigned int)); //writes a 32bit unsigned integer to the stream, in binary format (will span 4 characters).

  my_stream.write("not a null-terminated string", 28); //write a set of characters (no null-termination) 

  
  my_stream.seekg(starting_pos); //go back to the start to see if we can read the content again.

  string test;
  getline(my_stream,test,'\0'); //read a null-terminated string in the variable "test".

  cout << test << endl; //print out the result.
  
  for(int i=0;i<42;++i) { //this loop will print out the content of buf (with # marks for null-characters).
    if(buf[i] == 0)
      cout << '#';
    else 
      cout << buf[i];
  };
  cout << endl;

  return 0;
};

So here is my intention, I am going to take the code you gave me, utilize it along side with the std::vector<char> I have been using, and create a second std::vector<char>. Have one for reading, and one for writing. How would i use an dynamiaclly set buffer? Since vector is dynamicaly set, i can't pass the value of 42....I could just do something very large (e.g. 1024*1024)

Here is how I think i need to setup the reader, please correct me if I am wrong.

std::vector<char> outputDrsVector;
stringstream inputDrsStream;
inputDrsStream.rdbuf()->pubsetbuf(outputDrsVector, 1024*1024); // legal?
unsigned int test;
inputDrsStream.read(test, 4); // correct?

Ty For the help :) I really appreciate it, this is probably not the best way to go around it, but when i have already written 1200 lines of code, I don't want to change much right now, this conversion project has definitely been different from how I would normally write a program like this....

No, the code you have is not legal. If you are stuck having to use a vector of chars, then I can suggest you do the following workaround:

std::vector<char> outputDrsVector;
outputDrsVector.resize(1024); //make sure the vector is not empty!!! Replace the 1024 by a meaningful number (not a magical number).
stringstream inputDrsStream;
inputDrsStream.rdbuf()->pubsetbuf(&outputDrsVector[0], outputDrsVector.size()); // legal.
unsigned int test;
inputDrsStream.write(test, sizeof(unsigned int)); // correct.

Normally, I would not recommend the above because it requires to be very careful:
This assumes that you have already a vector that is big enough to write all the content to. DO NOT GIVE AN EMPTY VECTOR TO PUBSETBUF. You must preallocate (using resize) enough memory in your vector to contain all the data that you will write to it. DO NOT USE THE VECTOR WHILE YOU ARE USING THE STRINGSTREAM ON IT. Using the vector in anyway after you have passed it to pubsetbuf and before you are completely finished with the stringstream will cause a crash. ALWAYS PASS size() TO THE PUBSETBUF FUNCTION. Do not make up some magic number for the "maximum" size, use the size() function of the vector to obtain its size.

For reading and writing integer values (or others), never use magic numbers for size like the "4" that you put in your posted code. Always use the sizeof() operator. DO NOT ASSUME THAT int OR unsigned int ARE 4 BYTES (32bit) LONG. The sizes of these variables varies depending on the operating system and compiler (this is true for all primitive types, except "char" which is guaranteed to be 1). If you need to have fixed-size integer types (and I am almost certain that you do!), use the C library "stdint.h", it has types like int32, uint32, int64, uint64, int16, etc.

>>this conversion project has definitely been different from how I would normally write a program like this....
Program conversions are always a big nightmare... I usually try to stay as far away from that as I can. I never do conversions because I know it's almost always less trouble to just re-implement it from scratch (or wrap it in a DLL or something). And I never use code that has been converted from another language, because I have learned that translations are usually full of small, insidious bugs (once, we almost destroyed a robot because of code that was mistranslated from Fortran to C, I won't do that mistake again!).

I need to read from one vector and write to the second :S Using 2 sstreams here.... 2 vectors. sorry if i got you confused with my bad variable names.

Maybe I am getting confused between read and write...

Read-> take and store into the stream.
Write-> write out from the stream to the vector.

std::vector<char> inputDrsVector;
inputDrsVector.resize(1024); //make sure the vector is not empty!!! Replace the 1024 by a meaningful number (not a magical number).
stringstream inputDrsStream;
inputDrsStream.rdbuf()->pubsetbuf(&inputDrsVector[0], inputVector.size()); // legal.
unsigned int test;
inputDrsStream.read(test, sizeof(unsigned int)); // read or write?

Maybe I am getting confused between read and write...

Read-> take and store into the stream.
Write-> write out from the stream to the vector.

You are confused about the process. The stream does not store memory. Only the vector<char> store the memory. So, what you do is you start with an input vector<char>, link it to a stringstream object, then, using the stream you can access the memory directly to read-off all those values you need to alter. Then you figure out how large the output vector needs to be. Create an output vector<char> that is of the right size (using resize or through the constructor). Then you link this vector to another stringstream object, which you use to write all those values into the output vector. Finally, you return the output vector as a result of the function.

The C# code that you posted does this in a slightly different (and quite stupid) way. But, hey, what do you expect from a C# programmer anyways?

Anyhow, since this is dragging on, I just translated the C# code you posted, except for the parts between /****/ lines and a few things at the end. I hope that you can figure out the rest, because I cannot make it any clearer at this point (I've run out of things to explain).

#include <iostream>
#include <sstream>
#include "stdint.h"

vector<char> Decode(vector<char>& data) {

    stringstream reader;
    reader.rdbuf()->pubsetbuf(&data[0],data.size()); // create variable        

    // testing patch version
    uint32 version; reader.read(reinterpret_cast<char*>(&version),sizeof(version));
    if (version != 0x4e302e32)
        return data;

    uint32 framecount; reader.read(reinterpret_cast<char*>(&framecount),sizeof(framecount)); 
    if (framecount != 1)
        return data;

    char comment[24]; reader.read(comment,24);
    uint32 linesOffset; reader.read(reinterpret_cast<char*>(&linesOffset),sizeof(linesOffset)); 
    uint32 maskOffset; reader.read(reinterpret_cast<char*>(&maskOffset),sizeof(maskOffset)); 
    uint32 paletteOffset; reader.read(reinterpret_cast<char*>(&paletteOffset),sizeof(paletteOffset));
    uint32 properties; reader.read(reinterpret_cast<char*>(&properties),sizeof(properties));

    int32 width; reader.read(reinterpret_cast<char*>(&width),sizeof(width)); 
    if (width != oldWidth)
        return data;

    int32 height; reader.read(reinterpret_cast<char*>(&height),sizeof(height)); 
    int32 centerX; reader.read(reinterpret_cast<char*>(&centerX),sizeof(centerX)); 
    int32 centerY; reader.read(reinterpret_cast<char*>(&centerY),sizeof(centerY)); 

    // if height - centerY doesnt equal oldHeight return data due to error
    if (height - centerY != oldHeight)
        return data;

    if (centerY != 0)
    {
        int higher = newHeight - oldHeight;
        centerY -= higher;
        newHeight = oldHeight = height;
    }

    uint32 newMaskSize = (uint32) (newHeight*4);
    uint32 newLinesOffset = maskOffset + newMaskSize;
    uint32 newLinesSize = (uint32) (newHeight*4);
    uint32 newLineDataStart = newLinesOffset + newLinesSize;



    vector<char> newSlp(data.size()); //data.size() is probably not the right size, you should be able calculate the right size for the vector from counting all the written bytes in the code below..
    stringstream writer;
    writer.rdbuf()->pubsetbuf(&newSlp[0],newSlp.size()); //var outStream = new MemoryStream();
    //var writer = new BinaryWriter(outStream);
	//std::ofstream writer(outstream, std::ios::out | std::ios::binary);

    // Added by Master_G for testing purposes
    // UserFeedback.Info(string.Format("Resizing image #{0} for {1}x{2} to {3}x{4}",
    //    id, oldWidth, oldHeight, newWidth, newHeight));

    // writing the information provided above

    writer.write(reinterpret_cast<char*>(&version),sizeof(version));
    writer.write(reinterpret_cast<char*>(&framecount),sizeof(framecount));
    writer.write(comment,24);
    writer.write(reinterpret_cast<char*>(&newLinesOffset),sizeof(newLinesOffset));
    writer.write(reinterpret_cast<char*>(&maskOffset),sizeof(maskOffset));
    writer.write(reinterpret_cast<char*>(&paletteOffset),sizeof(paletteOffset));
    writer.write(reinterpret_cast<char*>(&properties),sizeof(properties));
    writer.write(reinterpret_cast<char*>(&newWidth),sizeof(newWidth));
    writer.write(reinterpret_cast<char*>(&newHeight),sizeof(newHeight));
    writer.write(reinterpret_cast<char*>(&centerX),sizeof(centerX));
    writer.write(reinterpret_cast<char*>(&centerY),sizeof(centerY));

    //UserFeedback.Info(string.Format("Version: {0}, FrameCount: {1}, Comment: {2}, newLinesOffset: {3}",
    //    version, framecount, comment, newLinesOffset));
    //UserFeedback.Info(string.Format("MaskOffSet: {0}, PaletteOffset: {1}, Properties: {2}",
    //    maskOffset, paletteOffset, properties));
    //UserFeedback.Info(string.Format("NewWidth: {0}, NewHeight: {1}, CenterX {2}, CenterY {3}",
    //   newWidth, newHeight, centerX, centerY));

    // read every line of pixels from file into orgLineMasks array
    uint32* orgLineMasks = new uint32[oldHeight];
    reader.read(reinterpret_cast<char*>(orgLineMasks),oldHeight*sizeof(uint32));

    // read every original line start of old height into array
    uint32* orgLineStarts = new uint32[oldHeight + 1];
    reader.read(reinterpret_cast<char*>(orgLineStarts),oldHeight*sizeof(uint32));
    orgLineStarts[oldHeight] = (uint32) data.size();


/*******************************************************************************************/
    // Subtract the next piece in orgLineStarts from the previous piece
    // and then store into a new variable called orgLines
    var orgLines = new List<byte[]>(oldHeight);
    for (var inLine = 0; inLine < oldHeight; inLine++)
    {
        var orgLineSize = orgLineStarts[inLine + 1] - orgLineStarts[inLine];
        orgLines.Add(reader.ReadBytes((int) orgLineSize));
    }

    // initialize new lists
    var newLineMasks = new UInt32[newHeight];
    var newLines = new List<byte[]>(newHeight);

    // difference in the lines from oldHeight compared to newHeight
    // e.g. 1200 - 1024 = 176
    int extraLines = newHeight - oldHeight;

    // determine whether shrinking resolution or expanding it
    int shrinking = extraLines < 0;
    int expanding = extraLines > 0; 

    // define middle of oldHeight
    // e.g. 1024/2 = 512
    int centreLine = oldHeight / 2;

    // e.g. 512 + 176 = 688
    int shrinkSkipStart = centreLine + extraLines;
    int shrinkSkipEnd = centreLine;

    // duplication is the amount of times every duplicated line, is duplicated
    // e.g. duplication = 1 + (176 + 1)/(1024/2)
    // e.g. duplication = 1.34570
    int duplication = 1 + (extraLines + 1)/(oldHeight/2);
    // the duplication block size is the block that is being duplicated
    // the last line of which MIGHT not be duplicated 'duplication' times
    //  eg if duplication is 2, extralines = 501, dbs = 251, the last of which is
    //  duped just once.
    int duplicationBlockSize = (extraLines + duplication - 1)/duplication;

    int dupStart = centreLine - duplicationBlockSize / 2;
    int dupEnd = dupStart + duplicationBlockSize;

    int dupedLines = 0; //'UNIT'TEST
    for (int inLine = 0; inLine < oldHeight; inLine++)
    {
        // If shrinking skip 'extralines' lines on the centerline and above
        if (shrinking && inLine >= shrinkSkipStart && inLine < shrinkSkipEnd)
        {
            dupedLines--;
            continue;
        }
        // newLineMasks has same ammount of positions as newHeight
        // e.g. 1200 => 1200
        // 
        newLineMasks[newLines.Count] = orgLineMasks[inLine];

        var newLine = StretchLine(orgLines[inLine], oldWidth, newWidth);
        newLines.Add(newLine);

        // If expanding, duplicate the right amount of lines before centreLine
        if (!expanding || inLine < dupStart || inLine >= dupEnd)
            continue;

        for (var rep = 0; rep < duplication && dupedLines < extraLines; rep++)
        {
            newLineMasks[newLines.Count] = orgLineMasks[inLine];
            newLines.Add(newLine);
            dupedLines++;
        }
    }

/*******************************************************************************************/

    uint32 nextLineStart = newLineDataStart;

    writer.write(reinterpret_cast<char*>(newLineMasks),newHeight*sizeof(uint32));

    foreach (var newLine in newLines)
    {
        writer.Write(nextLineStart);
        nextLineStart += (uint)newLine.Length;
    }

    foreach (var newLine in newLines)
        writer.Write(newLine);

    delete[] orgLineMasks; // DON'T FORGET TO DELETE EVERYTHING THAT YOU ALLOCATE WITH "new".
    delete[] orgLineStarts;
    delete[] newLineMasks;

    return newSlp; //since writer is linked to newSlp, all the data should be now writen to newSlp, and it can be returned.
};

Ok, I understand it now :) Tyvm :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.