I've got two methods in my Windows Forms application for parsing some gzip encoded strings.
Here are my two methods, which both return the same value.
public static async Task<string> DecodeGzipAsync(string str)
{
var values = new Dictionary<string, string>
{
{ "data", str }
};
var content = new FormUrlEncodedContent(values);
var client = new HttpClient();
var response = await client.PostAsync("http://www.txtwizard.net/compression/decompress/gz", content);
var json = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<GzipData>(json);
return result.DecompressedData;
}
public static string DecodeGzip(string str)
{
byte[] gzBuffer = Convert.FromBase64String(str);
using (MemoryStream ms = new MemoryStream())
{
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 0, gzBuffer.Length);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
{
zip.Read(buffer, 0, buffer.Length);
}
return Encoding.UTF8.GetString(buffer);
}
And then I call these two methods from my main form.
var string1 = await Utilities.DecodeGzipAsync(xml.InnerText);
var string1Concat = string.Concat("<Connotes>", string1, "</Connotes>");
var string2 = Utilities.DecodeGzip(xml.InnerText);
var string2Concat = string.Concat("<Connotes>", string2, "</Connotes>");
Where xml.InnerText is
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
The results I get are really frustrating (and weird!)
string1 and string2 both return the same string, however string1Concat and string2Concat return different results.
string1Concat = "<Connotes>" + string1 + "</Connotes>"
string2Concat = "<Connotes>" + string2 // Notice how it is missing the concatenation on the end
What might be causing this behaviour? I have tried changing the encoding to ASCII and UTF8 but both give the same results.
Any help is much appreciated!
This was a little tricky, but I found the problem/solution:
You convert the array of the size of the compressed data to a string at Encoding.UTF8.GetString(buffer). This will create a string which a length of 559903 instead of the correct 9209. If you create a new byte-array with the actually read bytes it is working:
public static string DecodeGzip(string str)
{
byte[] gzBuffer = Convert.FromBase64String(str);
using (MemoryStream ms = new MemoryStream())
{
int msgLength = BitConverter.ToInt32(gzBuffer, 0);
ms.Write(gzBuffer, 0, gzBuffer.Length);
byte[] buffer = new byte[msgLength];
ms.Position = 0;
int length;
using (GZipStream zip = new GZipStream(ms, CompressionMode.Decompress))
{
length = zip.Read(buffer, 0, buffer.Length);
}
var data = new byte[length];
Array.Copy(buffer, data, length);
return Encoding.UTF8.GetString(data);
}
}
Related
I'm using the below code to compress the stream using SevenZip, and it produces an output which I write back into filesystem.
private static byte[] Compress(byte[] input)
{
var inputStream = new MemoryStream(input);
var outputStream = new MemoryStream();
Int32 dictionarySize = 1 << 16;
string matchFinder = "bt4";
Int32 numFastBytes = 128;
CoderPropID[] propIDs =
{
CoderPropID.DictionarySize
,CoderPropID.MatchFinder
,CoderPropID.NumFastBytes
};
object[] properties =
{
(Int32)(dictionarySize)
,matchFinder
,(Int32)(numFastBytes)
};
SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
encoder.SetCoderProperties(propIDs, properties);
encoder.WriteCoderProperties(outputStream);
outputStream.Write(BitConverter.GetBytes(inputStream.Length), 0, 8);
encoder.Code(inputStream, outputStream, inputStream.Length, -1, null);
outputStream.Flush();
outputStream.Close();
return outputStream.ToArray();
}
But when I try to DeCompress the output file, using below code it throws error
System.OverflowException: 'Array dimensions exceeded supported range.
at line coder.SetDecoderProperties(properties);.
private static void DecompressFileLZMA(string inFile, string outFile)
{
SevenZip.Compression.LZMA.Decoder coder = new SevenZip.Compression.LZMA.Decoder();
FileStream input = new FileStream(inFile, FileMode.Open);
FileStream output = new FileStream(outFile, FileMode.Create);
// Read the decoder properties
byte[] properties = new byte[5];
input.Read(properties, 0, 5);
// Read in the decompress file size.
byte[] fileLengthBytes = new byte[8];
input.Read(fileLengthBytes, 0, 8);
long fileLength = BitConverter.ToInt64(fileLengthBytes, 0);
coder.SetDecoderProperties(properties);
coder.Code(input, output, input.Length, fileLength, null);
output.Flush();
output.Close();
}
I'm not able to find out what is incorrect in SetDecoderProperties?
I have 3 images in a directory but my code always returns one of them. I'd like to return 3 images image1.jpg, image2.jpg, image3.jpg and get them in my Xamarin app.
I think returning the result like an array might solve the problem but I don't understand what I need.
var result = new HttpResponseMessage(HttpStatusCode.OK);
MemoryStream ms = new MemoryStream();
for (int i = 0; i < 3; i++)
{
String filePath = HostingEnvironment.MapPath("~/Fotos/Empresas/Comer/" + id + (i + 1) + ".jpg");
FileStream fileStream = new FileStream(filePath, FileMode.OpenOrCreate);
Image image = Image.FromStream(fileStream);
image.Save(ms, ImageFormat.Jpeg);
fileStream.Close();
byte[] bytes = File.ReadAllBytes(filePath);
byte[] length = BitConverter.GetBytes(bytes.Length);
// Write length followed by file bytes to stream
ms.Write(length, 0, 3);
ms.Write(bytes, 0, bytes.Length);
}
result.Content = new StreamContent(ms);
return result;
Now i getting bytes, i edit a little bit the code now
byte[] imageAsBytes = client.GetByteArrayAsync(url).Result;
MemoryStream stream1 = new MemoryStream(imageAsBytes);
img.Source = ImageSource.FromStream(() => { return stream1; });
this is my xamarin code to get images, but i still getting nothing =/
If you just return a memorystream is not easy to differentiate one image from the other in the stream, instead of this, you can return a List of byte arrays, then you can access each position in the array and convert from byte array to image...
Here is a fully functional dotnet core webapi controller :
public class GetImagesController : Controller
{
private readonly IWebHostEnvironment _host;
public GetImagesController(IWebHostEnvironment host)
{
_host = host;
}
[HttpGet("{images}")]
public async Task<List<byte[]>> Get([FromQuery]string images)
{
List<byte[]> imageBytes = new List<byte[]>();
String[] strArray = images.Split(',');
for (int i = 0; i < strArray.Length; i++)
{
String filePath = Path.Combine(_host.ContentRootPath, "images", strArray[i]+".jpg");
byte[] bytes = System.IO.File.ReadAllBytes(filePath);
imageBytes.Add(bytes);
}
return imageBytes;
}
}
This controller can be called like this :
https://localhost:44386/getImages?images=P1,P2,P3
Given that you have a folder called images with files P1.jpg, P2.jpg and P3.jpg under your ContentRooPath.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-3.0
You'll need something in the response to delimit where each image starts and finishes. As a basic solution, you could write the image length as an Int32 and follow it with the image data. On the other end, you'll need to read the 4-byte length followed by that x number of bytes:
[HttpGet]
public HttpResponseMessage Get(string id)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
String[] strArray = id.Split(',');
var ms = new MemoryStream();
for (int i = 0; i < strArray.Length; i++)
{
String filePath = HostingEnvironment.MapPath("~/Fotos/Empresas/Comer/" + strArray[i] + (i + 1) + ".jpg");
byte[] bytes = File.ReadAllBytes(filePath);
byte[] length = BitConverter.GetBytes(bytes.Length);
// Write length followed by file bytes to stream
ms.Write(length, 0, 4);
ms.Write(bytes, 0, bytes.Length);
}
result.Content = new StreamContent(ms);
return result;
}
I am compressing a json using deflate compression technique and saving to sql server database. The json contains values from any culture ie. th-TH, zh-TW. The compressed string is getting saved successfully in database.
Json includes data like {"#id":"2113","description":"อาหารเช้าคอนติเนนทัล"}
Now when i read the same data from db, i convert it to bytes as
Encoding encoding = Encoding.UTF8;
encoding.GetBytes(data ?? string.Empty)
The compression like this
public static string Compress(this string data, CompressionTypeOptions compressionType)
{
var bytes = Compress(Encoding.UTF-8.GetBytes(data ?? string.Empty), compressionType);
return Encoding.UTF-8.GetString(bytes);
}
}
private static byte[] Compress(byte[] data, CompressionTypeOptions compressionType)
{
using (var memoryStream1 = new MemoryStream(data))
{
using (var memoryStream2 = new MemoryStream())
{
using (var compressionStream = CreateCompressionStream(compressionType, (Stream)memoryStream2,
CompressionMode.Compress))
{
CopyTo((Stream)memoryStream1, compressionStream);
compressionStream.Close();
return memoryStream2.ToArray();
}
}
}
}
Then decompressing like this
using (var memoryStream = new MemoryStream(data))
{
using (var compressionStream = CreateCompressionStream(compressionType, (Stream)memoryStream,
CompressionMode.Decompress))
return ReadAllBytesFromStream(compressionStream);
}
Here is ReadAllBytesFromStream definition
private static byte[] ReadAllBytesFromStream(Stream stream)
{
using (var memoryStream = new MemoryStream())
{
var buffer1 = new byte[1];
while (true)
{
int count = stream.Read(buffer1, 0, 1);
if (count != 0)
memoryStream.Write(buffer1, 0, count);
else
break;
}
var length = memoryStream.Length;
var buffer2 = new byte[length];
memoryStream.Position = 0L;
memoryStream.Read(buffer2, 0, (int)length);
return buffer2;
}
}
Getting error at int count = stream.Read(buffer1, 0, 1); as
'System.IO.InvalidDataException'
'Unknown block type. Stream might be corrupted.'
Any help is appreaciated
I receive a zip file base64 string, convert to byte[], open in memory, modify content, and then 'compress' the new byte[] to base64 string again.
My problem, I don't know how to 'compress' the new byte[] to zip format.
public string ModifyZipContent(string base64) {
ZipPackage zipPackage = null;
MemoryStream memoryStream = null;
long lenght;
byte[] data = Convert.FromBase64String(base64);
byte[] buffer;
byte[] newData;
int arrayOffset = 0;
memoryStream = new MemoryStream();
memoryStream.Write(data, 0, data.Length);
zipPackage = (ZipPackage)Package.Open(memoryStream, FileMode.Open);
PackagePartCollection zipParts = zipPackage.GetParts();
// this is awful
foreach(ZipPackagePart zipPart in zipParts) {
using(Stream stream = zipPart.GetStream()) {
arrayOffset += (int)stream.Length;
}
}
newData = new byte[arrayOffset];
// end
arrayOffset = 0;
foreach(ZipPackagePart zipPart in zipParts) {
using(Stream stream = zipPart.GetStream()) {
lenght = stream.Length;
buffer = new byte[lenght];
stream.Read(buffer, 0, (int)lenght);
Buffer.BlockCopy(buffer, 0, newData, arrayOffset, buffer.Length);
arrayOffset += buffer.Length;
}
}
return Convert.ToBase64String(newData);
}
I haven't fully tested this, but something along these lines should work...
// Requires System.IO.Compression using statement.
byte[] bytes = new byte[256]; // Your byte[] would be here instead of this empty one.
using (var zipFile = ZipFile.Open("C:/ZipFile.zip", ZipArchiveMode.Update))
{
var entry = zipFile.CreateEntry("YourEntryPathHere");
using (var stream = entry.Open())
{
stream.Write(bytes, 0, bytes.Length);
}
}
I spent 3 hours searching for how to uncompress a string using Zlib.net.dll and I did not find anything useful.
Since my string is compressed by the old VB6 program that uses zlib.dll and I do not want to use file access each time I want to uncompress a string.
The problem is you need to know what the original size of the byte[] is before compression.
Or you can use dynamic array for decoding the data.
The code is here:
private string ZlibNetDecompress(string iCompressData, uint OriginalSize)
{
byte[] todecode_byte = Convert.FromBase64String(iCompressData);
byte[] lDecodeData = new byte[OriginalSize];
string lTempoString = System.Text.Encoding.Unicode.GetString(todecode_byte);
todecode_byte = System.Text.Encoding.Default.GetBytes(lTempoString);
string lReVal = "";
MemoryStream outStream = new MemoryStream();
MemoryStream InStream = new MemoryStream(todecode_byte);
zlib.ZOutputStream outZStream = new zlib.ZOutputStream(outStream);
try
{
CopyStream(InStream, outZStream);
lDecodeData = outStream.GetBuffer();
lReVal = System.Text.Encoding.Default.GetString(lDecodeData);
}
finally
{
outZStream.Close();
InStream.Close();
}
return lReVal;
}
private void CopyStream(System.IO.Stream input, System.IO.Stream output)
{
byte[] buffer = new byte[2000];
int len;
while ((len = input.Read(buffer, 0, 2000)) > 0)
{
output.Write(buffer, 0, len);
}
output.Flush();
}
You could use the GZipStreamClass from the framework.
var data = new byte[resultSizeMax];
using (Stream ds = new DeflateStream(stream, CompressionMode.Decompress))
for (var i=0; i< 1000; i+=ds.Read(data, i,1000-i);