I have been trying to get a simple byte array in to a Picture box using c#. Most examples I tried give me parameter invalid. If I don't use a using or converter and break it out like so (see code below) I do get an image but it looks wrong (all black with some random colored dots up top).
Bitmap bmp = new Bitmap(48, 32, PixelFormat.Format24bppRgb);
BitmapData bmpData = bmp.LockBits(
new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.WriteOnly, bmp.PixelFormat);
Marshal.Copy(blob, 0, bmpData.Scan0, blob.Length);
bmp.UnlockBits(bmpData);
return bmp;
The byte array looks like this.
01 c7 f0 70 3f 03 00 c3 f0 60 1e 01 80 63 ff c3 1c 71 88 21 ff c7 3c f3 8e 31 f0 c7 fc ff 86 31 f0 c7 fc ff c4 31 f0 c1 fc 3f c0 31 e0 e0 7e 0f c0 f1 e1 f8 3f 83 c0 31 e1 fe 1f e1 c6 31 e0 ff 9f f9 86 30 f0 fb 9c 79 8f 38 f0 e3 98 79 8f 38 f8 63 98 79 80 30 38 62 1c 61 80 70 10 70 3e 03 ff ff ff ff ff ff ff ff ff ff ff ff 00 7e 00 78 7f f0 88 3c 18 18 3f f0 8e 3c 7e 0f 0f c3 86 30 ff 07 87 87 c4 31 ff 87 e0 8f c0 71 ff e7 f8 0f c0 71 ff e7 f0 0f c0 71 ff e7 f0 0f c6 71 ff e7 f0 1f 86 10 ff 87 e1 1f 8f 18 ff 8f 87 87 8f 18 7f 0f 0f c3 80 1c 0c 18 3f f0 80 7e 00 38 7f f0
My image should be 192 bytes and a 48 x 32 res image. What am I doing wrong?
As Michael Liu commented, if your data is 192 bytes, and you need to get 32 lines of data out of that, then each line will be 6 bytes, meaning that to get 48 pixels out of such a line, you need to multiply it by 8, or, in other words, use 1 bit per pixel, which is PixelFormat.Format1bppIndexed.
As for your problems in visualizing the data, you need to take the stride into account; the actual amount of bytes per line of pixels.
Images created by the .Net framework always use a multiple of four bytes as width of each line of pixels, so the new 48x32 image you make will have 8 bytes on each line. However, your image data is completely compact data, so it only has 6 bytes per line.
So you need to copy it line by line, keeping the stride of both your input and output into account. This means you should replace the single Marshal.Copy by a loop over the height that does one Marshal.Copy per line, copying the data per 6 bytes from the input array to the correct start pointer of each line on the output.
The adjusted Marshal.Copy operation should be something like this:
Int32 newDataWidth = ((Image.GetPixelFormatSize(pixelFormat) * width) + 7) / 8;
Int32 targetStride = bmpData.Stride;
Int64 scan0 = bmpData.Scan0.ToInt64();
for (Int32 y = 0; y < height; y++)
Marshal.Copy(blob, y * stride, new IntPtr(scan0 + y * targetStride), newDataWidth);
...with stride the stride of your input array (so in this case, 6).
To automate the input stride calculation, if you know you have completely compact data, you can use the formula I already kind of showed in the previous block:
public static Int32 GetMinimumStride(Int32 width, Int32 bitsLength)
{
return ((bitsLength * width) + 7) / 8;
}
I already posted code here on SO to build an image from bytes in any format, so you can just use that, I guess. Using that BuildImage function, you can build your image like this:
public static Bitmap BuildMonoBitmap(Byte monoBytes, Int32 width, Int32 height)
{
Color[] pal = new Color[] {Color.Black, Color.White};
Int32 stride = GetMinimumStride(width, 1);
return BuildImage(monoBytes, width, height, stride, PixelFormat.Format1bppIndexed, pal, null);
}
The result, shown in my test program:
Related
I am using the following code to read a psuedo-HTTP request response. It works sometimes but not always and I do not understand.
Background: I have a device that takes HTTP GET requests and sends a chunked HTTP response. In one case, the response is not a proper chunked HTTP response. It leaves out the null chunk that indicates the end of data. I have fixed that problem in the device, but I am trying to figure out how to read the non-comforming HTTP response. I found code from Create http request using TcpClient that sometimes works and sometimes doesn't and I do not understand why.
If I use the code unaltered, it works fine. If I use it by replacing the "www.bing.com" with my device's IP, "192.1.168.89" in both places the string appears, for example, and change the GET command line to "GET /index.htm HTTP/1.1", it works fine. This version of the command returns a web page that is constructed by the device and sends several TCP buffers (about 1400 bytes in my device) of chunked data.
However, if I change to another command that my device understands, "GET /request.htm?T HTTP/1.1", but returns less than 500 bytes of chunked data, then I never see the response. In fact it never gets past the call to "CopyToAsync(memory)" and I do not understand why. The device sees the request, parses it and sends a proper HTTP response. (I know it is a proper response because I have code that uses HTTPClient to read the response and it sees the response fine. And I see the response data from the device side is exactly the same going out in both cases. I can see the device data because I am writing the device's firmware and can change it to printf() the data being sent out to the TCP routines.)
Anyone have an explanation for why the code below isn't always seeing a response?
private static async Task<string> HttpRequestAsync() {
string result = string.Empty;
using (var tcp = new TcpClient("www.bing.com", 80))
using (var stream = tcp.GetStream())
{
tcp.SendTimeout = 500;
tcp.ReceiveTimeout = 1000;
// Send request headers
var builder = new StringBuilder();
builder.AppendLine("GET /?scope=images&nr=1 HTTP/1.1");
builder.AppendLine("Host: www.bing.com");
//builder.AppendLine("Content-Length: " + data.Length); // only for POST request
builder.AppendLine("Connection: close");
builder.AppendLine();
var header = Encoding.ASCII.GetBytes(builder.ToString());
await stream.WriteAsync(header, 0, header.Length);
// Send payload data if you are POST request
//await stream.WriteAsync(data, 0, data.Length);
// receive data
using (var memory = new MemoryStream())
{
await stream.CopyToAsync(memory);
memory.Position = 0;
var data = memory.ToArray();
var index = BinaryMatch(data, Encoding.ASCII.GetBytes("\r\n\r\n")) + 4;
var headers = Encoding.ASCII.GetString(data, 0, index);
memory.Position = index;
if (headers.IndexOf("Content-Encoding: gzip") > 0)
{
using (GZipStream decompressionStream = new GZipStream(memory, CompressionMode.Decompress))
using (var decompressedMemory = new MemoryStream())
{
decompressionStream.CopyTo(decompressedMemory);
decompressedMemory.Position = 0;
result = Encoding.UTF8.GetString(decompressedMemory.ToArray());
}
}
else
{
result = Encoding.UTF8.GetString(data, index, data.Length - index);
//result = Encoding.GetEncoding("gbk").GetString(data, index, data.Length - index);
}
}
//Debug.WriteLine(result);
return result;
}
}
private static int BinaryMatch(byte[] input, byte[] pattern)
{
int sLen = input.Length - pattern.Length + 1;
for (int i = 0; i < sLen; ++i)
{
bool match = true;
for (int j = 0; j < pattern.Length; ++j)
{
if (input[i + j] != pattern[j])
{
match = false;
break;
}
}
if (match)
{
return i;
}
}
return -1;
}
=====================
Let me edit the function above to show what it is now and maybe clarify things.
static async Task<byte[]> getTcpClientHttpDataRequestAsync(string ipAddress, string request)
{
string result = string.Empty;
List<byte> arrayList = new List<byte>();
using (var tcp = new TcpClient("192.168.1.89", 80))
using (var stream = tcp.GetStream())
using (var memory = new MemoryStream())
{
tcp.SendTimeout = 500;
tcp.ReceiveTimeout = 10000;
tcp.NoDelay = true;
// Send request headers
var builder = new StringBuilder();
builder.AppendLine("GET /request.htm?x01011920000000000001 HTTP/1.1");
builder.AppendLine("Host: 192.168.1.89");
builder.AppendLine("Connection: Close");
builder.AppendLine();
var header = Encoding.ASCII.GetBytes(builder.ToString());
Console.WriteLine("======");
Console.WriteLine(builder.ToString());
Console.WriteLine("======");
await stream.WriteAsync(header, 0, header.Length);
do { } while (stream.DataAvailable == 0);
Console.WriteLine("Data available");
bool done = false;
do
{
int next = stream.ReadByte();
if (next < 0)
{
done = true;
}
else
{
arrayList.Add(Convert.ToByte(next));
}
} while (stream.DataAvailable && !done);
byte[] data = arrayList.ToArray();
return data;
}
}
The GET command is what my device is responding to. If the command starts with 'x' as shown then it responds with a proper HTTP response and the function above reads the data. If it starts with 'd' it is missing the 0 length chunk at the end and the function above never sees any data from the device.
With Wireshark, I am seeing the following responses for the 'x' and 'd' commands.
The 'x' command returns 2 TCP frames with the following data:
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 9c 00 47 00 00 64 06 d2 49 c0 a8 01 59 c0 a8 ...G..d..I...Y..
0020 01 22 00 50 05 5d fc f5 9e 72 ad 75 e3 2c 50 18 .".P.]...r.u.,P.
0030 00 01 a9 cd 00 00 48 54 54 50 2f 31 2e 31 20 32 ......HTTP/1.1 2
0040 30 30 20 4f 4b 0d 0a 43 6f 6e 6e 65 63 74 69 6f 00 OK..Connectio
0050 6e 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e n: close..Conten
0060 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm
0070 6c 0d 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c l..Cache-Control
0080 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 54 72 61 6e : no-cache..Tran
0090 73 66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 sfer-Encoding: c
00a0 68 75 6e 6b 65 64 0d 0a 0d 0a hunked....
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 45 00 48 00 00 64 06 d2 9f c0 a8 01 59 c0 a8 .E.H..d......Y..
0020 01 22 00 50 05 5d fc f5 9e e6 ad 75 e3 2c 50 18 .".P.].....u.,P.
0030 00 01 fc 20 00 00 30 30 31 0d 0a 2b 0d 0a 30 30 ... ..001..+..00
0040 37 0d 0a 01 85 86 00 00 0d 0a 0d 0a 30 30 30 0d 7...........000.
0050 0a 0d 0a ...
By comparison the 'd' command returns data in 2 TCP frames as:
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 9c 00 4e 00 00 64 06 d2 42 c0 a8 01 59 c0 a8 ...N..d..B...Y..
0020 01 22 00 50 05 5e d3 c3 f9 f5 69 cc 6d a3 50 18 .".P.^....i.m.P.
0030 00 01 30 ae 00 00 48 54 54 50 2f 31 2e 31 20 32 ..0...HTTP/1.1 2
0040 30 30 20 4f 4b 0d 0a 43 6f 6e 6e 65 63 74 69 6f 00 OK..Connectio
0050 6e 3a 20 63 6c 6f 73 65 0d 0a 43 6f 6e 74 65 6e n: close..Conten
0060 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 68 74 6d t-Type: text/htm
0070 6c 0d 0a 43 61 63 68 65 2d 43 6f 6e 74 72 6f 6c l..Cache-Control
0080 3a 20 6e 6f 2d 63 61 63 68 65 0d 0a 54 72 61 6e : no-cache..Tran
0090 73 66 65 72 2d 45 6e 63 6f 64 69 6e 67 3a 20 63 sfer-Encoding: c
00a0 68 75 6e 6b 65 64 0d 0a 0d 0a hunked....
0000 1c 6f 65 d3 f0 e2 4c 60 de 41 3f 67 08 00 45 00 .oe...L`.A?g..E.
0010 00 36 00 4f 00 00 64 06 d2 a7 c0 a8 01 59 c0 a8 .6.O..d......Y..
0020 01 22 00 50 05 5e d3 c3 fa 69 69 cc 6d a3 50 18 .".P.^...ii.m.P.
0030 00 01 64 c2 00 00 30 30 37 0d 0a 01 90 91 00 00 ..d...007.......
0040 0d 0a 0d 0a ....
The only discernible differences that I see is that in the second frame of the 'd' command it is missing a 1 byte chunk that is part of our protocol (and shouldn't have any effect on the TCP/HTTP function) and the last 7 bytes of data that the 'x' command provides, which is the 0 length chunk expected for HTTP.
Going back to the code in HttpRequestAsync(), if the 'd' command is sent then the code never sees stream.DataAvailable become true, even though the data has been sent. Why?
await stream.CopyToAsync()
will not complete until
stream.DataAvailable == false
You have indicated to the server, in the headers that you will close the TCP connection when done, but have not done so. The server will eventually close the connection when it thinks you're gone. The server is not obligated to obey your "Connection: close" request and that should be indicated in the headers the server returns.
Before you call stream.CopyToAsync() you should check the headers to determine if what Content-Length has been supplied and pass a buffer length to stream.CopyToAsync() and then call TcpClient.Close()
I'm trying to generate a public key with BouncyCastle (because I'm using Unity and do not have access to ECDiffieHellmanCng), and then I transfer the public key to the server which is using ECDiffieHellmanCng for its key handling.
The server is rejecting my key, for what appears to be because of its small length. ECDiffieHellmanCng generates a public key that is much larger in size compared to that of what Bouncy castle generates.
Is there a way to generate a larger key in bouncy castle?
I tried changing the keybit size, but get an error saying: InvalidParameterException: unknown key size.
Key that BouncyCastle generates:
3059301306072A8648CE3D020106082A8648CE3D03010703420004272F71C1D8B3DC0A7FCB1E9650EEF64EA8F639BEC97D49F8848455C2F5869F7324332D188129C84727F834EE7EE7D8EB7DFC8D40CD4ED219A4FBCEF6C15200F3
Key that ECDiffieHellmanCng generates:
45434B35420000000055CC8665A66A7CDF2E9BF7C69A25B322C72CDBDB1EA8F348050B0A7CF32F9AAD890EA513583367977D5157B2F7FBF55661C9AE2DBAF09B1DC1EA8F193688C3C09501BEE326867ABCB41CA1029F66AF888649F0A6C0674D19670CF32461BA7B3867C1623D68829A7A9A7F1CFC6F5DB99E13C8D960AEF6F5CDAB5B3B62ED6CBEC7222C9F
Here is the code thats generating the bouncy castle key:
const string Algorithm = "ECDH";
const int KeyBitSize = 256;
const int NonceBitSize = 128;
const int MacBitSize = 128;
const int DefaultPrimeProbability = 30;
IAsymmetricCipherKeyPairGenerator aliceKeyGen = GeneratorUtilities.GetKeyPairGenerator(Algorithm);
DHParametersGenerator aliceGenerator = new DHParametersGenerator();
aliceGenerator.Init(KeyBitSize, DefaultPrimeProbability, new SecureRandom());
DHParameters aliceParameters = aliceGenerator.GenerateParameters();
KeyGenerationParameters aliceKGP = new DHKeyGenerationParameters(new SecureRandom(), aliceParameters);
aliceKeyGen.Init(aliceKGP);
AsymmetricCipherKeyPair aliceKeyPair = aliceKeyGen.GenerateKeyPair();
IBasicAgreement aliceKeyAgree = AgreementUtilities.GetBasicAgreement(Algorithm);
aliceKeyAgree.Init(aliceKeyPair.Private);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(aliceKeyPair.Public);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
string serializedPublic = AsString(serializedPublicBytes);
public static string AsString(byte[] bytes, bool keepDashes = false)
{
string hex = BitConverter.ToString(bytes);
return (keepDashes ? hex : hex.Replace("-", ""));
}
I also tried the Mentalis.org DH library, which gives me a larger key, but still just a hair too short.
// create a new DH instance
DiffieHellman dh1 = new DiffieHellmanManaged();
// generate the public key of the first DH instance
byte[] ke1 = dh1.CreateKeyExchange();
string publicKeyString = AsString(ke1);
Key from mentalis.org library:
5F4542F9A8F5636ECCBBAC38238C97ABE757B8F65E25B181BCF41C58985E699EFD6B9606B99F7074717E83F7AC1B5E97DFF6DBA94876F74645F25F0D7FAA1528898C1BD0BB568DF15A98724093766B213769893A05B47E40410B0F395C834F68F57B2EE01852895D912C1D56675A7D8C5367B5E06DE08AAA18CBB4C69F3AE142
If you were to decode the BouncyCastle version you'd see that it is
30 59
SEQUENCE
30 13
SEQUENCE
06 07 2A 86 48 CE 3D 02 01
OBJECT IDENTIFIER 1.2.840.10045.2.1 (id-ecPublicKey)
06 08 2A 86 48 CE 3D 03 01 07
OBJECT IDENTIFIER 1.2.840.10045.3.1.7 (id-secp256r1)
03 42 00
BIT STRING
04 27 2F 71 C1 D8 B3 DC 0A 7F CB 1E 96 50 EE F6
4E A8 F6 39 BE C9 7D 49 F8 84 84 55 C2 F5 86 9F
73 24 33 2D 18 81 29 C8 47 27 F8 34 EE 7E E7 D8
EB 7D FC 8D 40 CD 4E D2 19 A4 FB CE F6 C1 52 00
F3
The BIT STRING's payload is the encoded value of an ecPublicKey whose curve is secp256r1.
Then, following 2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion from the SEC-1 paper we see that it's encoded as
04
Uncompressed Point
X = 27 2F 71 C1 D8 B3 DC 0A 7F CB 1E 96 50 EE F6 4E
A8 F6 39 BE C9 7D 49 F8 84 84 55 C2 F5 86 9F 73
Y = 24 33 2D 18 81 29 C8 47 27 F8 34 EE 7E E7 D8 EB
7D FC 8D 40 CD 4E D2 19 A4 FB CE F6 C1 52 00 F3
Following the logic from the .NET Core import/export ECC feature we see that the equivalent CNG blob is
// BCRYPT_ECDH_PUBLIC_P256_MAGIC (little-endian)
45 43 B4 31
// cbKey=(DWORD)32 (little-endian)
20 00 00 00
// The X bytes (big-endian):
27 2F 71 C1 D8 B3 DC 0A 7F CB 1E 96 50 EE F6 4E
A8 F6 39 BE C9 7D 49 F8 84 84 55 C2 F5 86 9F 73
// The Y bytes (big-endian):
27 2F 71 C1 D8 B3 DC 0A 7F CB 1E 96 50 EE F6 4E
A8 F6 39 BE C9 7D 49 F8 84 84 55 C2 F5 86 9F 73
Sorry for the lengthy post I'm trying to give as much information as I can and I did my best to format everything to be as easily readable as possible. I've been trying to decompress GIF's in C# and seem to have everything except the LZW decompression down. I am reading in the Gif from a URL. For this example, I will be using this Animated GIF. Which I know has 35 Frames but I only want to look at the first one.
HEADER: 474946383961
GIF Version: 89a
LOGICAL DESCRIPTOR: 41003D00F60000
Width : 65
Height: 61
Sorted Color Table: False
Global Color Table Size: 128
Background Color Index: 0
Pixel Bits: 0
Below is the Global Color Table, something I am slightly confused about because it is filled 123/128 colors and the rest are 000000s, do I discredit this while filling the code table?
Sorry about the format here, only showing it for the question regarding the 000000s
Global Color Table:
141414 181818 1C1C1C 242424 262626 282828 2A2A2A 2C2C28 302C2C 30302C 3430303 434303
434344 030185 030284 03C346 038306 438306 43C305 044245 048245 448285 C50285C 502C5C
542C5C 543054 503860 542C68 50286C 50286C 542870 542870 542C70 582874 582870 582C745
82C745 C2C785 C2C605 830645 830645 C30645 C34685 C307C6 02C6C6 0346C6 438746 434786
030786 838786 C3C006 464806 02C806 42C806 430846 C34886 C348C7 034847 43C887 0388C7
43C887 83C8C7 83C907 034947 034947 434987 434947 438987 4389C7 8389C7 C38A07 838A07
C388C7 C40A46 050A48 03C948 048A08 848A08 C48A89 04CA89 44CAC9 44CAC9 850B09 C50B49
C50B49 C54B4A 054BCA 050B8A 054B8A 454BCA 454BCA 458BCA C5CC0A 454C0A 854C0A 858C4A
858C4A C58C4A C5CC8A C58C8A C5CC4B 058C8B 058C8B 05CC89 C64C8B 060CCB 460D0B 860D0B
864D4B C64D4C 068D8C 068D8C 468DCC 468DCC 86CE8D 070ECD 874F0D C78F4D C78F4D C7CF4E
078F8E 07CF8E 47C000 000000 000000 000000 000000 000000
Graphics Control Extension
21F9040D03007B00 |Graphics Control Extension
Block Size: 4
Has Transparency: True
Delay: 768
Transparency Color Index: 123
Image Descriptor
IMAGE DESCRIPTOR: 2C0000000041003D0000
Left: 0
Top: 0
Width : 65
Height: 61
Local Color Table: False
Interlace: False
Finally Where I am confused the Image Data
LZW minimum code size: 7
IMAGE DATA SUBBLOCK 1 HEXDATA:
80 7B 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 86 06 06 90 94 84 07
95 86 05 0C 00 98 94 05 01 07 05 9D 7B 05 0B 9B A3 8F 07 0C 0C 02 05
93 94 07 08 0A 09 9C A8 8D 05 08 B2 04 02 AF A9 09 0B 0A B5 B6 8B 05
00 C0 AB 01 A2 8E 05 BF C0 C2 C3 8A 07 0A 08 AB 0F 19 CA 8C A5 C0 0B
CF D0 88 C5 0C 09 0C 08 6E 29 CB 0C 0B A6 DD DE 87 9A E9 4C 67 2A D8
89 06 0C 0A E9 08 EB EC 85 06 00 BF 58 63 C6 C8 5B 64 40 4B BA 05 B4
F6 11 03 F0 20 60 18 37 03 E9 85 41 90 4E 43 05 85 C4 AA 9C 39 43 E6
8C 0C 15 8A 0A 98 E9 58 A6 0A 05 8C 21 29 90 21 33 86 0C 98 88 99 C0
8C D9 38 E6 22 CA 90 13 58 86 21 23 05 45 81 9F 40 81 5A 09 C8 F2 E4
CD 94 1D 37 5C D0 93 A7 A9 D3 A6 2A 7C 8C 34 63 F2 28 B1 09 14 EE D8
A9 B3 B5 8E 57 AE 76 B8 AC 68 49 66 82 D5 6C 75 E2 A8 55 0B 67 6D 1C
For All intensive purposes We should need to look at the first few binary bits
IMAGE BLOCK BINARY:
10000000 clearcode, 01111011, 10000010, 10000011, 10000100,
10000101, 10000110, 10000111, 10001000, 10001001, 10001010,
10001011, 10001100, 10001101, 10001110, 10001111,
Codes:
1000000, 0011110, 1110000, 01010000... ect
My main question is how do I use LSB Packing order when reading these codes, secondly how does this make sense for each pixel considering the background is transparent, like how do I get the index of the first non transparent pixel. Finally, at what point do I increase the code size for adding codes to the table to LZW Minimum codes size +1(8). Thank you for any advice.
LSB packing order just means to read the data as little-endian and right shift the data as you "eat" the bits.
Here's an example in C, C# makes accessing memory more painful, but the logic would be the same:
uint32_t ulBits;
unsigned char *pData;
int codelen, code, bitnum;
int mask;
int nextcode;
codelen = 7; // assume 7 bits to start
mask = (1<<(codelen+1)) -1;
clearcode = (mask >> 1) + 1;
nextcode = clearcode + 2;
ulBits = *(uint32_t)pData; // read 32-bits as little endian
bitnum = 0;
#define WORDLEN 32
// To read the variable length codes you would do the following:
while (decoding == true)
{
if ((bitnum + codelen) > WORDLEN) // need to read more data
{
pData += (bitnum >> 3); // adjust source pointer
ulBits = *(uint32_t)pData; // read another 32-bits
bitnum &= 7; // reset bit offset
}
code = (ulBits >> bitnum);
code &= mask;
bitnum += codelen;
// some logic here to increment the nextcode is beyond the scope of this answer
<the rest of your logic here>
}
As you decompress the codes, you add a new item to your dictionary and increment your "next code" value. When this value can't fit in the current code size, you increase it by one bit until you hit 4096 and usually start over with a clear code to reset the dictionary. There is a rarely used option called "differed clear code". In this case the full dictionary stays in use until a clear code is received. There are plenty of sample LZW decoders that you can look at, so it's not necessary to post an entire one here.
Hello I'm trying to pass data from a pointer to a struct but the values seem to be different.
struct somestruct
{
public file header;
public uint version;
}
unsafe struct file
{
public fixed char name[8];
public uint type;
public uint size;
}
Then in code somewhere..
public unsafe int ReadFile(string filepath)
{
somestruct f = new somestruct();
byte[] fdata = System.IO.ReadAllBytes( filepath );
fixed( byte* src = fdata )
{
f.header = *(file*)src;
MessageBox.Show( new string(f.header.name) ); //should be 'FILENAME' but it's like japanese.
}
return 0;
}
Offset(h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
00000000 46 49 4C 45 4E 41 4D 45 00 00 00 01 00 00 00 30 FILENAME.......0
00000010 74 27 9F EF 74 77 F1 D7 C5 86 93 3D 39 0D 72 A9 t'Ÿïtwñ×ņ“=9.r©
00000020 63 8B 92 CF F6 7D 8A 14 45 9D 68 51 A4 8E A4 EE c‹’Ïö}Š.E.hQ¤Ž¤î
00000030 4E FE D0 66 45 0E C9 8D 96 BB F4 EE 52 1F 89 D3 NþÐfE.É.–»ôîR.‰Ó
00000040 5C 80 1A 71 8A 16 B1 8B 3A A8 1B A4 48 11 B8 E8 \€.qŠ.±‹:¨.¤H.¸è
Do you have any idea what's going on?
Each char is 2 bytes - a fixed buffer of 8 chars is 16 bytes. You are reading the first 8 bytes as only the first 4 characters in that buffer, and the high bytes will make it look. Like the eastern Unicode ranges.
I would say: deserialize it at the stream level. Don't do this.
Basically, read (at least) 20 bytes into a buffer, then decode manually, using:
string s = Encoding.ASCII.GetString(buffer, 0, 8);
For the string, and probably shift operations for the unsigned integers.
You could also use unsafe code to read the integers from the buffer, via the other meaning of fixed and a pointer-cast.
A char is UTF-16 and is 2 bytes. You need to convert the UTF-8/ANSI (1 byte) string to a UTF-16 string.
I have a string variable from which I get the following bytes with the following loop:
Bytes I get: 1e 05 55 3c *e2 *91 6f 03 *fe 1a 1d *f4 51 6a 5e 3a *ce *d1 04 *8c
With that loop:
byte[] temp = new byte[source.Length];
string x = "";
for (int i = 0;i != source.Length;i++)
{
temp[i] = ((byte) source[i]);
}
Now I have wanted to simplify that operation and use Encoding's GetBytes.
The problem is I cannot fit an appropriate encoding. e.g. I get several bytes incorrect:
Encoding.ASCII.GetBytes(source): 1e 05 55 3c *3f *3f 6f 03 *3f 1a 1d *3f 51 6a 5e 3a *3f *3f 04 *3f
Encoding.Default.GetBytes(source): 1e 05 55 3c e2 3f 6f 03 3f 1a 1d f4 51 6a 5e 3a ce 4e 04 3f
How can I get rid of that loop and use Encoding's GetBytes?
Here is the summary:
Loop(correct bytes): 1e 05 55 3c *e2 *91 6f 03 *fe 1a 1d *f4 51 6a 5e 3a *ce *d1 04 *8c
Encoding.ASCII.GetBytes(source): 1e 05 55 3c *3f *3f 6f 03 *3f 1a 1d *3f 51 6a 5e 3a *3f *3f 04 *3f
Encoding.Default.GetBytes(source): 1e 05 55 3c e2 3f 6f 03 3f 1a 1d f4 51 6a 5e 3a ce 4e 04 3f
Thanks!
Addition:
I have a string input in hex, sth like: "B1807869C20CC1788018690341"
then I transfer this into string with the method:
private static string hexToString(string sText)
{
int i = 0;
string plain = "";
while (i < sText.Length)
{
plain += Convert.ToChar(Convert.ToInt32(sText.Substring(i, 2), 16));
i += 2;
}
return plain;
}
Your hexToString is transferring byte values (via hex) directly to unicode code-points in the range 0-255. As it happens, that ties into code-page 28591, so if you use:
Encoding enc = Encoding.GetEncoding(28591);
and use that enc, you should get the right data; however, a more important point here is that binary data is not the same as text data, and you should not use a string to hold arbitrary binary.
Presuming that you are trying to "decode" a string literal:
C# stores the strings as Unicode internally.
So you might want to use a encoding that (correctly) supports Unicode
such as:
Encoding.UTF8.GetBytes(source)
Encoding.UnicodeEncoding.GetBytes(source)
Note the caution given for Encoding.Default in MSDN