问题
I am trying to convert a AS3 (ActionScript 3) function to C#.
This ActionScript function contains a class called ByteArray which from what I am aware of it's basically what it sounds like lmao. I think it's kind of similar of how byte[] would be in C#. Anyway, I have tried my best to convert the code to C# using MemoryStream and then writing bytes to it, and then returning UTF8 string as you can see in my code below. However, I feel as if my way of doing how the ActionScript code does isn't accurate and that is where my question above comes in.
With them negative numbers being written into "loc1" (The ByteArray) and "loc1.uncompress()", that's where I feel like I am failing and was wondering if someone could help me out in converting this function so it's fully accurate?
On top of that question, I would also like to ask if what I was doing with the negative numbers was correct in my C# code just like how the ActionScript code was doing it? Would mean a lot (:
(Sorry if not fully understandable and if what I say doesn't match up as much)
ActionScript Code:
private function p() : String
{
var _loc1_:ByteArray = new ByteArray();
_loc1_.writeByte(120);
_loc1_.writeByte(-38);
_loc1_.writeByte(99);
_loc1_.writeByte(16);
_loc1_.writeByte(12);
_loc1_.writeByte(51);
_loc1_.writeByte(41);
_loc1_.writeByte(-118);
_loc1_.writeByte(12);
_loc1_.writeByte(50);
_loc1_.writeByte(81);
_loc1_.writeByte(73);
_loc1_.writeByte(49);
_loc1_.writeByte(-56);
_loc1_.writeByte(13);
_loc1_.writeByte(48);
_loc1_.writeByte(54);
_loc1_.writeByte(54);
_loc1_.writeByte(14);
_loc1_.writeByte(48);
_loc1_.writeByte(46);
_loc1_.writeByte(2);
_loc1_.writeByte(0);
_loc1_.writeByte(45);
_loc1_.writeByte(-30);
_loc1_.writeByte(4);
_loc1_.writeByte(-16);
_loc1_.uncompress();
_loc1_.position = 0;
return _loc1_.readUTF();
}
My C# Code:
public string p()
{
MemoryStream loc1 = new MemoryStream();
loc1.WriteByte((byte)120);
loc1.WriteByte((byte)~-38);
loc1.WriteByte((byte)99);
loc1.WriteByte((byte)16);
loc1.WriteByte((byte)12);
loc1.WriteByte((byte)51);
loc1.WriteByte((byte)41);
loc1.WriteByte((byte)~-118);
loc1.WriteByte((byte)12);
loc1.WriteByte((byte)50);
loc1.WriteByte((byte)81);
loc1.WriteByte((byte)73);
loc1.WriteByte((byte)49);
loc1.WriteByte((byte)~-56);
loc1.WriteByte((byte)13);
loc1.WriteByte((byte)48);
loc1.WriteByte((byte)54);
loc1.WriteByte((byte)54);
loc1.WriteByte((byte)14);
loc1.WriteByte((byte)48);
loc1.WriteByte((byte)46);
loc1.WriteByte((byte)2);
loc1.WriteByte((byte)0);
loc1.WriteByte((byte)45);
loc1.WriteByte((byte)~-30);
loc1.WriteByte((byte)4);
loc1.WriteByte((byte)~-16);
loc1.Position = 0;
return Encoding.UTF8.GetString(loc1.ToArray());
}
回答1:
(1)
@Jimmy has given you a good Answer.
This is what he meant when he told you "to mask with 0xFF" so that your -38 becomes masked as:
loc1.WriteByte( (byte)(-38 & 0xFF) );
Do the same above logic for any other values that have a minus sign.
(2)
It might be easier if you just use values written in hex instead of decimal. This means instead of decimal 255 you write equivalent hex of 0xFF since bytes are supposed to be in hex. The WriteByte is auto-converting your decimals but it's not helping you to learn what it is going on...
For example your beginning two byte values are 120 -38 but in hex that is 0x78 0xDA.
Now if you google search bytes 0x78 0xDA you will find out those two bytes are header for ZLIB's DEFLATE compression algorithm.
This ZLIB detail is important to know for the next step...
(3)
Sometimes the variable names are not always recovered during de-compiling. This is why all your code has these silly _loc_ as generic names (real var names are unknown, only their data type).
Your _loc1_.uncompress(); is supposed to contain a String variable specifying the algorithm.
public function uncompress(algorithm:String) :void//from AS3 documentation
During decompilation that important info was lost. Luckily there only 3 options "ZLIB", "DEFLATE" or "LZMA". From the above notice (2) we can see it should be _loc1_.uncompress("DEFLATE");
Solution:
Create a byte array (not Memory Stream) and manually fill with hex values (eg: -13 is written 0xDA).
First convert each of your numbers to hex. You can use Windows Calculator in Programmer mode (under View option), where you type a decimal in dec mode then press hex to see same value as hex format. Maybe some online tool can do it too.
The final hex values should look like 78 DA 63 10 0C 33 29 8A 0C 32 51 49 31 C8 .... etc until the ending hex value F0 which equals your ending decimal -16.
Then you can easily do...
public string p()
{
byte[] loc_Data = new byte[] {
0x78, 0xDA, 0x63, 0x10, 0x0C, 0x33, 0x29, 0x8A,
0x0C, 0x32, 0x51, 0x49, 0x31, 0xC8, 0x0D, 0x30, etc etc ... until 0xF0
};
var loc_Uncompressed = Ionic.Zlib.ZlibStream.UncompressBuffer( loc_Data );
return Encoding.UTF8.GetString( loc_Uncompressed ); //or try: loc_Uncompressed.ToArray()
}
回答2:
1) In C#, bytes are unsigned. You cannot convert a signed byte to an unsigned byte with the complement, because your intention is that the bitwise representation should be identical, rather than opposite, which is what the complement does.
one simple way to convert is to mask with 0xFF: -37 & 0xFF = 219. There are other, mathematically equivalent ways, such as checking for negatives with sbyte sb = -37; byte b = sb < 0 ? 256 + sb : sb;
2) The builtin System.IO.Compression namespace is lacking in a number of ways. For one, it doesn't even support decompressing zlib data, which is what your byte array holds. the best way is to use a third party package on Nuget instead. The DotNetZip library does what you need, specifically the Ionic.Zlib.ZlibStream.UncompressBuffer function.
来源:https://stackoverflow.com/questions/57532311/what-is-bytearray-uncompress-in-as3-equivalent-to-in-c