Parse a string to a *packed* Integer. (0xFFFFFFFF)

ok, so, I can’t seem to find a solid answer on how to do this and it’s driving me crazy. My game uses integers for item colors parsed out of a .properties file initially on launching a new game or generating new items, since all my equipment is drawn in gray scale and colored in game. Problem is, the color is applied with a packed integer, and I can’t seem to figure out how to convert the string in my .properties files from my external data into something the engine can use.

Example of one of my generic item files: tshirt.properties
type=shirt
name=shirt_tshirt
nameProper=T-Shirt
color=0xFFFF0000 <–a “red” shirt, basically. RGBA: 255,0,0,255
value=10
weight=5

Well, I need to convert those values, including the x, into an Integer to pass to my Color class, but I can’t seem to find a way to. Integer.parseInt throws back an error because it doesnt know how to handle the 0x part, I also tried a few various ways of Byte.parseByte and none of those work either.

I could easily just take the RGB values as 3 different properties then combine them all into a packed Integer, but then I’d have to have 3 property lines in all my files/saves/etc for every single item everywhere just to store the colors, and have to do 3 ugly Integer.parseInts to pull them out. Just bad news all around. Be nice if I can keep the ugly Integer parsing down to only pulling 1 value. :confused:

Here’s an example of the actual code, specifically for reading the player’s skin color when it loads the game.

Fired when the game loads, to color the character’s skin:

public static int getSkinColor(){return getPropertyAsInt("skinColor", "0xFFFFFFFF");}

…that fires:


	public static int getPropertyAsInt(String p, String n){
		try {
			playerProperties.getProperty(p).toString();
		} catch (NullPointerException npe) {
			playerProperties.setProperty(p, n);
		}
		return Integer.parseInt(playerProperties.getProperty(p));
	}

Basically, it takes the value p and looks for it in the properties file, if it’s not found it assigns it to n. (Basically n is the default value). But the error is thrown at return Integer.parseInt(playerProperties.getProperty§); because it can’t figure out what to do with the 0x part of the packed int.

Any suggestions that will allow me to keep my packed int in my property files? :o

There is a few ways you can handle your issue. You can use bit shifts and bit masks to hide the data and extract the numbers you need from the hexadecimal. Or, you can use this…

http://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#decode(java.lang.String)

Which is also useful for converting data into numbers. The bit shift and bit mask things are a bit tricky to pull off. If you need an example, I’ll see if I have some old code running around that does it.

Yep, Integer.decode() is what you want.

Even if you didn’t realize that, I don’t see why you couldn’t parseInt(playerProperties.getProperty(p).substring(2));

And to get the hex from an int:


String hex = "0x" + Integer.toHexString(i).toUpperCase();

Oh, there is another solution if you are allowed to use the [icode]java.awt[/icode] class.

You can make a java.awt.Color out of any hex by using this code…


//For RGBA - like what you have in your example
Color thisColor = new Color(Integer.decode("<your hex here>"), true);

//Then just extract the colors from thisColor

A little bit less efficient, but a lot more direct.

It sounds like he doesn’t need the individual channels, but if he does, or needs the Color object anyway, then that’s fine.

Of course direct unpacking goes like so:


//assuming ARGB representation: 0xAARRGGBB
int p = Integer.decode(s);
int a = p >> 24;
int r = p >> 16 & 0xFF;
int g = p >> 8 & 0xFF;
int b = p & 0xFF;

Holy crap java! … Ok, I found a solution (thanks to you guys for pushing me in the right direction).

Basically, I ended up having to do decode with a Long, instead of an Integer:
Long.decode(0xHEXVALUE).intValue();

Basically, any value that flips to a negative when parsed with Integer.decode() implode java, but Long.decode doesn’t have that problem. Here’s where I found the ultimate solution:

But in a nutshell, Integer.decode(); can’t parse values over 0x7FFFFFFF because they become “negative integers” when converted to base10 ints and Integer.decode() requires positive numbers to work with, making it basically useless for what I needed since the first 2 digits are my alpha channel in my colors. So unless my players don’t mind everything being a little transparent, no dice. But, Long.decode() can take care of it, no problem what so ever.

Here’s another thread explaining the negative integer deal:
https://community.oracle.com/message/8607000

On a side note, after further research I discovered why this is, when you convert 0xFFFFFFFF from hex to decimal, it’s 4294967295. Well, max int size in java is 2147483647, So I guess it does some number-wrapping and rolls it all the way around into negatives. So I am going to assume that’s the problem, in the process of the Int converting the string over to a Hex value at once point and time it has to store it as a base10 int, and well, it can’t hold it. But a Long can!

Either way, thanks for the help! Works like a champ now. :smiley:

You have experienced Integer Overflow.

Although I did not know of that decode() issue. Huh.

Wow, that decode() behaviour really is a nasty gotcha.
First bug reported against it… 15 years ago. :-\

Even worse are Integer’s parseInt & valueOf methods, as they make no mention of any special behaviour or limitation relating to integer values >0x7FFFFFFF.

hah. yep. I never thought decode() would cause it. I guess it makes sense, since at one point in time in the process I am assuming it has to break the hex string into base10 and then work it back into base16. But what I don’t understand is if that is the case, why not just make that one step a Long? I guess with ultra-heavy database work if you’re running decode a million times a second using a Long would slow everything down…

yeah, I found out the hard way too. I spent about 2 hours trying to get this what-should-be very simple code to work, LOL.

I guess it won’t be fixed in the near future, for backwards compatibility issues, and the workarounds for it is trivial. That’s just a conclusion I have thought up when hypothesizing that the bug, it being reported it 15 years ago, still exists today.