Whats the best way to do Int to MemoryBlock?


#1

Whats the best way to do Int to MemoryBlock? 4byte
And MemoryBlock back to Int…

I come from a .NET background so most of this is handled within the framework. I need this for bitwise checking of licenses.


#2

I think this works going to MemoryBlock

MemoryBlock productIdBytes(static_cast<char*>(static_cast<void*>(&productId)),4);


#3

For bitwise checking you could use the BigInteger class instead:
https://www.juce.com/doc/classBigInteger


#4

Cheers but really could do with conversion. Bitwise comparison is quite straight forward in byte array (or MemoryBlock) and Juce uses MemoryBlock for hash data SHA256 MD5 e.t.c. which I can replicate what my platform does (.NET) to generate licenses

Did notice my example to convert to memoryBlock the endianness is back to front. However I can convert back now

int back = ((Bytes[0]<<24)|(Bytes[1]<<16)|(Bytes[2]<<8)|(Bytes[3]));


#5

FYI casting the address of a local variable is undefined behaviour, and a lot of compilers will generate broken code at high optimisation levels.

Best to use the methods in juce::ByteOrder, which are designed to clarify endianness issues like this.


#6

Cheers, will look at that now

I went down this as a solution to endianness which seems to work but if ByteOrder is more elegant than great

int productId = 14;

Byte block[4];

auto p = static_cast<char*>(static_cast<void*>(&productId));
block[0]=p[3];
block[1]=p[2];
block[2]=p[1];
block[3]=p[0];

MemoryBlock productIdBytes(block,4);

#7

Is Juce missing a MemoryBlock toHex function?


#8

Honestly, don’t do a cast like that, it’ll end in tears!

No, that doesn’t sound like an appropriate place for anything like that. Maybe String::toHexString?


#9

Well just a working solution for now. It builds on VS2015 and Xcode without issues. But I have wrapped them up in functions anyway so I can swap out for a better solution at a later date.

This is only for registering users with program so it only gets called infrequently (well just on startup).

For example this string
Parsing license : 12708C44A93E4D6F11AD46AD68FD04690ADC7529A3C8C6BF32535700FF2206D7-49616e204b6e6f776c6573

Generates this as a license structure which also does validation and decryptes against a cipher. I know there are better solutions but I already have a web platform in place to generate license keys in this format so wanted keep this in place for when I commercialise a product.

productId: 1
linkType: 1
accountId: 44
reserved: 0
accountName: Ian Knowles

int toInt(MemoryBlock mb, int offset){
    return ((mb[0+offset]<<24)|(mb[1+offset]<<16)|(mb[2+offset]<<8)|(mb[3+offset]));
};

MemoryBlock toMemoryBlock(int i ){
    Byte block[4];
    auto p = static_cast<char*>(static_cast<void*>(&i));
    block[0]=p[3];
    block[1]=p[2];
    block[2]=p[1];
    block[3]=p[0];
    MemoryBlock mb(block,4);
    return mb;
};

String toHex(MemoryBlock mb)
{
    String a;
    
    for(int i = 0; i < mb.getSize() ; i++) {
        a+= Hex[(Byte)mb[i]];
    }
    return a;
}

const String Hex[256] = { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF" };

#10

Ouch! Saying “it’s a working solution” is really really bad - the cast is undefined behaviour. It may seem to work now, but maybe in a few months you’ll change the compiler settings or build for a different CPU and it will begin to fail without you noticing.

And your toHex method is… ahem… interesting… Hopefully you typed all those strings correctly (!) and aren’t planning on calling it from a static constructor when the Strings may not yet even be initialised. But even so, you might want to replace the function with a single call to String::toHexString!


#11

I knew you’d like it hehe.
You think that’s bad you should see the lack of ScopedPointers used (which I am coming around to using now). Most components have delete on destructor. But no mem leaks so far :wink: - actually have had bad experience with scoped when using multiple threads probably because I don’t quite know the architecture principles so opted for calling delete on my own terms.

Nope that hex string isn’t static and nope I didn’t type them out. Just wrote a quick couple of for loops to spit out the hex chars quotations and comma’s.

I did need to go from MemoryBlock directly to hex though and I’m sure string would have barfed a little as the byte array contains a set of hash bytes which could be the full range of a byte.


#12

Converting a MemoryBlock to a hex string is as easy as String::toHexString(mb.getData(), mb.getSize()).

Jules, could you elaborate or link to further reading concerning the casting issue. I’d also expected that something like
MemoryBlock mb(static_cast<char*> (static_cast<void*> (&intVariable)), sizeof(int));
would work (although it certainly doesn’t look nice) and would like to understand the underlying problem.


#13

Yeah, casting the address of a local variable is undefined behaviour, and if the compiler decides to elide the local variable, things go horribly wrong (this isn’t just theoretical - I’ve actually been bitten by it in real code on various occasions before I learned my lesson, e.g. in an old version of juce::roundToInt). The only reliable way to reinterpret a local int in terms of bytes is by using a union.


#14

So would this be better then?

MemoryBlock toMemoryBlock(int i)
{
    
    MemoryBlock mb(4);
    mb[0] = i >> 24;
    mb[1] = i >> 16;
    mb[2] = i >> 8;
    mb[3] = i >> 0;
    
    return mb;
}

#15

Well, yes, that’s safe.

Or why not just create a MemoryOutputStream and push integers into it?