C++/CX How to convert from IRandomAccessStream^ to bytes and back. (UWP) - c++

So I have a stream, what I want to be able is to transfer it into unsigned char * bytes and back to usable stream.
This stream is image (it is binary if it is important?)
Basically what I am trying now is as follows:
IRandomAccessStream^ inputStream;
DataWriter^ dataWriter = ref new DataWriter(inputStream);
IBuffer^ buffer1 = dataWriter->DetachBuffer();
unsigned char * bytes = GetPointerToPixelData(buffer1);
DataWriter ^writer = ref new DataWriter();
writer->WriteBytes(Platform::ArrayReference<BYTE>(bytes, sizeof(bytes)));
task<DataWriterStoreOperation^>(writer->StoreAsync()).get();
task<Windows::Foundation::IAsyncOperation<bool>>(writer->FlushAsync()).get();
IBuffer ^buffer2 = writer->DetachBuffer();
IRandomAccessStream^ newStream;
task<Windows::Foundation::IAsyncOperationWithProgress<unsigned int, unsigned int>>(newStream->WriteAsync(buffer2)).get();
task<Windows::Foundation::IAsyncOperation<bool>>(newStream->FlushAsync()).get();
UseNewStream(newStream)
I have added all of these task<...> because it is not working without them, and I am not sure how to make it work?
Function GetPointerToPixelData I found online and is following:
byte* GetPointerToPixelData(IBuffer^ buffer)
{
// Cast to Object^, then to its underlying IInspectable interface.
Object^ obj = buffer;
ComPtr<IInspectable> insp(reinterpret_cast<IInspectable*>(obj));
// Query the IBufferByteAccess interface.
ComPtr<IBufferByteAccess> bufferByteAccess;
insp.As(&bufferByteAccess);
// Retrieve the buffer data.
byte* pixels = nullptr;
bufferByteAccess->Buffer(&pixels);
return pixels;
}
Thanks! :)

Firstly, if you want to transfer the image stream to bytes, you need to read the stream by DataReader, not by DataWriter which is for write data. Secondly, the DetachBuffer() method is for "Detaches the buffer that is associated with the data reader", not read the buffer. Lastly, DataReader can directly read bytes by ReadBytes(Byte[]) method. For example:
uint64 length = 0;
BYTE *extracted;
void CleanImagetobyte::MainPage::btnconverttobyte_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
create_task(KnownFolders::GetFolderForUserAsync(nullptr /* current user */, KnownFolderId::PicturesLibrary))
.then([this](StorageFolder^ picturesFolder)
{
return picturesFolder->GetFileAsync("B.jpg");
}).then([this](task<StorageFile^> task)
{
try
{
StorageFile^ file = task.get();
auto name = file->Name;
return file->OpenAsync(FileAccessMode::Read);
}
catch (Exception^ e)
{
// I/O errors are reported as exceptions.
}
}).then([this](task<IRandomAccessStream^> task)
{
IRandomAccessStream^ inputStream = task.get();
length = inputStream->Size;
IBuffer^ buffer = ref new Buffer(inputStream->Size);
inputStream->ReadAsync(buffer, inputStream->Size, InputStreamOptions::None);
DataReader^ reader = DataReader::FromBuffer(buffer);
extracted = new BYTE[buffer->Length];
reader->ReadBytes(Platform::ArrayReference<BYTE>(extracted, buffer->Length));
});
}
void CleanImagetobyte::MainPage::btnconvertback_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
create_task(KnownFolders::GetFolderForUserAsync(nullptr /* current user */, KnownFolderId::PicturesLibrary))
.then([this](StorageFolder^ picturesFolder)
{
return picturesFolder->CreateFileAsync("newB.jpg", CreationCollisionOption::ReplaceExisting);
}).then([this](task<StorageFile^> task)
{
StorageFile^ file = task.get();
Array<byte>^ arr = ref new Array<byte>(extracted, length);
FileIO::WriteBytesAsync(file, arr);
});
}
More details for read and write a file please reference this document.

Related

using a bytes field as proxy for arbitrary messages

Hello nano developers,
I'd like to realize the following proto:
message container {
enum MessageType {
TYPE_UNKNOWN = 0;
evt_resultStatus = 1;
}
required MessageType mt = 1;
optional bytes cmd_evt_transfer = 2;
}
message evt_resultStatus {
required int32 operationMode = 1;
}
...
The dots denote, there are more messages with (multiple) primitive containing datatypes to come. The enum will grow likewise, just wanted to keep it short.
The container gets generated as:
typedef struct _container {
container_MessageType mt;
pb_callback_t cmd_evt_transfer;
} container;
evt_resultStatus is:
typedef struct _evt_resultStatus {
int32_t operationMode;
} evt_resultStatus;
The field cmd_evt_transfer should act as a proxy of subsequent messages like evt_resultStatus holding primitive datatypes.
evt_resultStatus shall be encoded into bytes and be placed into the cmd_evt_transfer field.
Then the container shall get encoded and the encoding result will be used for subsequent transfers.
The background why to do so, is to shorten the proto definition and avoid the oneof thing. Unfortunately syntax version 3 is not fully supported, so we can not make use of any fields.
The first question is: will this approach be possible?
What I've got so far is the encoding including the callback which seems to behave fine. But on the other side, decoding somehow skips the callback. I've read issues here, that this happened also when using oneof and bytes fields.
Can someone please clarify on how to proceed with this?
Sample code so far I got:
bool encode_msg_test(pb_byte_t* buffer, int32_t sval, size_t* sz, char* err) {
evt_resultStatus rs = evt_resultStatus_init_zero;
rs.operationMode = sval;
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
/*encode container*/
container msg = container_init_zero;
msg.mt = container_MessageType_evt_resultStatus;
msg.cmd_evt_transfer.arg = &rs;
msg.cmd_evt_transfer.funcs.encode = encode_cb;
if(! pb_encode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sz = stream.bytes_written;
return true;
}
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
//with the below in place a stream full error rises
// if (! pb_encode_tag_for_field(stream, field)) {
// return false;
// }
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
//buffer holds previously encoded data
bool decode_msg_test(pb_byte_t* buffer, int32_t* sval, size_t msg_len, char* err) {
container msg = container_init_zero;
evt_resultStatus res = evt_resultStatus_init_zero;
msg.cmd_evt_transfer.arg = &res;
msg.cmd_evt_transfer.funcs.decode = decode_cb;
pb_istream_t stream = pb_istream_from_buffer(buffer, msg_len);
if(! pb_decode(&stream, container_fields, &msg)) {
const char* local_err = PB_GET_ERROR(&stream);
sprintf(err, "pb_encode error: %s", local_err);
return false;
}
*sval = res.operationMode;
return true;
}
bool decode_cb(pb_istream_t *istream, const pb_field_t *field, void **arg) {
evt_resultStatus * rs = (evt_resultStatus*)(*arg);
if(! pb_decode(istream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
I feel, I don't have a proper understanding of the encoding / decoding process.
Is it correct to assume:
the first call of pb_encode (in encode_msg_test) takes care of the mt field
the second call of pb_encode (in encode_cb) handles the cmd_evt_transfer field
If I do:
bool encode_cb(pb_ostream_t *stream, const pb_field_t *field, void * const *arg) {
evt_resultStatus* rs = (evt_resultStatus*)(*arg);
if (! pb_encode_tag_for_field(stream, field)) {
return false;
}
if(! pb_encode(stream, evt_resultStatus_fields, rs)) {
return false;
}
return true;
}
then I get a stream full error on the call of pb_encode.
Why is that?
Yes, the approach is reasonable. Nanopb callbacks do not care what the actual data read or written by the callback is.
As for why your decode callback is not working, you'll need to post the code you are using for decoding.
(As an aside, Any type does work in nanopb and is covered by this test case. But the type_url included in all Any messages makes them have a quite large overhead.)

How save in an array the following 100 received value after a determined received string in Qt

I'm a newbie in C++ and Qt. I want to save in an array the value received in a serialport after I received the string: "Data".
I'm using the terminal example so the serialport works properly.
The read function in the Example is the same:
void MainWindow::readData()
{
QByteArray data = serial->readAll();
console->putData(data);
}
How can I modify it? thanks!!!
If your manual sending the data i recommend you add a start of frame delimiter and an end of frame delimiter and checksum preferably.
QByteArray packet_storage;
just declare it the where you declare serial.
StartOfMessage and EndOfMessage will depend on your device.
I don't know what your transmitting. Hopefully you can figure out from the documentation of your device what your sending out.
as for me i am using
enum Constants
{
StartOfMessage = '\x02', /* Value of byte that marks the start of a message */
EndOfMessage = '\x03', /* Value of byte that marks the end of a message */
CarridgeReturn = '\x0D', /* Carridge return is first byte of end of line */
LineFeed = '\x0A', /* Line feed is second byte of end of line */
NullChar = '\0' /* Null Character */
};
void MainWindow::readData()
{
// read all
QByteArray data = serial->readAll();
// store all read data packet_storage is a QByteArray
packet_storage.append(data);
int start_index = 0;
int end_index = 0;
// process packet if not empty
if(!packet_storage.isEmpty())
{
if( packet_storage.contains(StartOfMessage) && packet_storage.contains(EndOfMessage))
{
start_index = packet_storage.indexOf(StartOfMessage,0);
end_index = packet_storage.indexOf(EndOfMessage,0);
int length = 0;
for (int i=start_index; i <= end_index; i++)
{
length++;
}
// get data
QByteArray dt = packet_storage.mid(start_index,length);
// do your processing here.
// store in vector write to file etc.
processpacket(dt);
packet_storage.remove(start_index,dt.size());
}
}
}

How to convert zip file containing xml into byte array without not using zipfile entries in java

I have a zip file containing xml file generated in Java.And I will send the zip file to Web Service in byte array format.The code snippet to convert zip file into byte array is
public static byte[] FileToArrayOfBytes(ZipFile file) throws IOException {
final Enumeration<? extends ZipEntry> entries = file.entries();
final ZipEntry entry = entries.nextElement();
BufferedInputStream istream = new BufferedInputStream(
file.getInputStream(entry));
int file_size = (int) entry.getCompressedSize();
byte[] blob = new byte[file_size];
int bytes_read = 0;
int offset = 0;
while ((bytes_read = istream.read(blob, 0, file_size)) != -1) {
offset += bytes_read;
}
file.close();
istream.close();
return blob;
}
When I send the byte array returned from above method,web service is returning an error message as 'invalid file extensions'.Normally we know web service accepts zip file.
Can you help me how can I handle the problem ?
I handled the my problem as following
public static byte[] convertFileIntoArrayOfBytes(String zipFilePath) {
FileInputStream fileInputStream = null;
File file = new File(zipFilePath);
byte[] bFile = new byte[(int) file.length()];
try {
// convert file into array of bytes
fileInputStream = new FileInputStream(zipFilePath);
fileInputStream.read(bFile);
fileInputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return bFile;
}

How to encrypt and decrypt a const char* in WinRT

I have been trying to write encrypt and decrypt functions whose signatures require the input and the output strings to be void* type only. The code works fine if the inputs can be specified as IBuffer^ but in the other case the source string and the encrypted->decrypted string do not match.
CodeIBuffer^ byteArrayToIBufferPtr(byte *source, int size)
{
Platform::ArrayReference<uint8> blobArray(source, size);
IBuffer ^buffer = CryptographicBuffer::CreateFromByteArray(blobArray);
return buffer;
}
byte* IBufferPtrToByteArray(IBuffer ^buffer)
{
Array<unsigned char,1U> ^platArray = ref new Array<unsigned char,1U>(256);
CryptographicBuffer::CopyToByteArray(buffer,&platArray);
byte *dest = platArray->Data;
return dest;
}
int DataEncryption::encryptData(EncryptionAlgorithm algo, int keySize, void* srcData, const unsigned int srcSize,
void*& encData, unsigned int& encSize)
{
LOG_D(TAG, "encryptData()");
if(srcData == nullptr)
{
LOG_E(TAG,"");
return DataEncryption::RESULT_EMPTY_DATA_ERROR;
}
if(srcSize == 0)
{
LOG_E(TAG,"");
return DataEncryption::RESULT_SIZE_ZERO_ERROR;
}
IBuffer^ encrypted;
IBuffer^ buffer;
IBuffer^ iv = nullptr;
String^ algName;
bool cbc = false;
switch (algo)
{
case DataEncryption::ENC_DEFAULT:
algName = "AES_CBC";
cbc = true;
break;
default:
break;
}
// Open the algorithm provider for the algorithm specified on input.
SymmetricKeyAlgorithmProvider^ Algorithm = SymmetricKeyAlgorithmProvider::OpenAlgorithm(algName);
// Generate a symmetric key.
IBuffer^ keymaterial = CryptographicBuffer::GenerateRandom((keySize + 7) / 8);
CryptographicKey^ key;
try
{
key = Algorithm->CreateSymmetricKey(keymaterial);
}
catch(InvalidArgumentException^ e)
{
LOG_E(TAG,"encryptData(): Could not create key.");
return DataEncryption::RESULT_ERROR;
}
// CBC mode needs Initialization vector, here just random data.
// IV property will be set on "Encrypted".
if (cbc)
iv = CryptographicBuffer::GenerateRandom(Algorithm->BlockLength);
// Set the data to encrypt.
IBuffer ^srcDataBuffer = byteArrayToIBufferPtr(static_cast<byte*>(srcData),256);
// Encrypt and create an authenticated tag.
encrypted = CryptographicEngine::Encrypt(key, srcDataBuffer, iv);
//encData = encrypted;
byte *bb = IBufferPtrToByteArray(encrypted);
encData = IBufferPtrToByteArray(encrypted);
encSize = encrypted->Length;
return DataEncryption::RESULT_SUCCESS;
}
int DataEncryption::decryptData(EncryptionAlgorithm algo, int keySize, void* encData, const unsigned int encSize,
void*& decData, unsigned int& decSize)
{
LOG_D(TAG, "decryptData()");
if(encData == nullptr)
{
LOG_E(TAG,"");
return DataEncryption::RESULT_EMPTY_DATA_ERROR;
}
if(encSize == 0)
{
LOG_E(TAG,"");
return DataEncryption::RESULT_SIZE_ZERO_ERROR;
}
IBuffer^ encrypted;
IBuffer^ decrypted;
IBuffer^ iv = nullptr;
String^ algName;
bool cbc = false;
switch (algo)
{
case DataEncryption::ENC_DEFAULT:
algName = "AES_CBC";
cbc = true;
break;
default:
break;
}
// Open the algorithm provider for the algorithm specified on input.
SymmetricKeyAlgorithmProvider^ Algorithm = SymmetricKeyAlgorithmProvider::OpenAlgorithm(algName);
// Generate a symmetric key.
IBuffer^ keymaterial = CryptographicBuffer::GenerateRandom((keySize + 7) / 8);
CryptographicKey^ key;
try
{
key = Algorithm->CreateSymmetricKey(keymaterial);
}
catch(InvalidArgumentException^ e)
{
LOG_E(TAG,"encryptData(): Could not create key.");
return DataEncryption::RESULT_ERROR;
}
// CBC mode needs Initialization vector, here just random data.
// IV property will be set on "Encrypted".
if (cbc)
iv = CryptographicBuffer::GenerateRandom(Algorithm->BlockLength);
// Set the data to decrypt.
byte *cc = static_cast<byte*>(encData);
IBuffer ^encDataBuffer = byteArrayToIBufferPtr(cc,256);
// Decrypt and verify the authenticated tag.
decrypted = CryptographicEngine::Decrypt(key, encDataBuffer, iv);
byte *bb = IBufferPtrToByteArray(decrypted);
decData = IBufferPtrToByteArray(decrypted);
decSize = decrypted->Length;
return DataEncryption::RESULT_SUCCESS;
}
I'm guessing that the problem is with this function:
byte* IBufferPtrToByteArray(IBuffer ^buffer)
{
Array<unsigned char,1U> ^platArray = ref new Array<unsigned char,1U>(256);
CryptographicBuffer::CopyToByteArray(buffer,&platArray);
byte *dest = platArray->Data;
return dest;
}
What you're doing there is allocating a new Platform::Array<byte>^ with 1 reference, then getting a pointer to its internally-managed storage, then returning that pointer-- at which point the Array is being dereferenced and is thus deallocating its underlying storage. Thus the pointer you return refers to freed memory. The next allocation is likely to overwrite those bytes.
What you'll need to do is take the return-by-reference Array<byte>^ from CopyToByteArray() (which creates a new Array, presumably wrapping the bytes of the input IBuffer^, and returns it) and copy that array's contents.
Your end result will function similarly to this snippet from the Readium SDK project, which takes a std::string instance, hashes it using SHA-1, and copies the hash data into a member variable uint8_t _key[KeySize]:
using namespace ::Platform;
using namespace ::Windows::Foundation::Cryptography;
using namespace ::Windows::Foundation::Cryptography::Core;
auto byteArray = ArrayReference<byte>(reinterpret_cast<byte*>(const_cast<char*>(str.data())), str.length());
auto inBuf = CryptographicBuffer::CreateFromByteArray(byteArray);
auto keyBuf = HashAlgorithmProvider::OpenAlgorithm(HashAlgorithmNames::Sha1)->HashData(inBuf);
Array<byte>^ outArray = nullptr;
CryptographicBuffer::CopyToByteArray(keyBuf, &outArray);
memcpy_s(_key, KeySize, outArray->Data, outArray->Length);
The steps:
Create an ArrayReference<byte> corresponding to the bytes in the std::string (no copying).
Pass that to CryptographicBuffer::CreateFromByteArray() to get your IBuffer^. Still no copying of data.
Call your hash/encryption function, passing the IBuffer^ you just made. You get another IBuffer^ in return, which may or may not be using the exact same storage (that's really up to the implementation of the algorithm, I think).
Create a variable of type Array<byte>^. Don't allocate an object, you're going to be given one by reference.
Pass the address of that object into CryptographicBuffer::CopyToByteArray() to receive a copy of your key data.
While that Array^ remains valid, copy its bytes into your native array.

TTS over web-service in compressed format

I have developed TTS engine in .NET. Now I want to expose it over web.
I have used the base64 string encoding to transfer the WAV format, but it is slow when I pass longer text.
Now I'm considering to build some MP3 streaming (maybe with NAudio) where I will convert the WAV formated MemoryStream into MP3 stream and pass it to the client. Does anyone has some experience with this?
Does anyone has experience how to convert WAV MemoryStream with NAudio to MP3 MemoryStream?
public class MP3StreamingPanel2 : UserControl
{
enum StreamingPlaybackState
{
Stopped,
Playing,
Buffering,
Paused
}
private BufferedWaveProvider bufferedWaveProvider;
private IWavePlayer waveOut;
private volatile StreamingPlaybackState playbackState;
private volatile bool fullyDownloaded;
private HttpWebRequest webRequest;
public void StreamMP32(string url)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");
section.HttpWebRequest.UseUnsafeHeaderParsing = true;
config.Save();
this.fullyDownloaded = false;
webRequest = (HttpWebRequest)WebRequest.Create(url);
int metaInt = 0; // blocksize of mp3 data
webRequest.Headers.Clear();
webRequest.Headers.Add("GET", "/ HTTP/1.0");
// needed to receive metadata informations
webRequest.Headers.Add("Icy-MetaData", "1");
webRequest.UserAgent = "WinampMPEG/5.09";
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
if (e.Status != WebExceptionStatus.RequestCanceled)
{
//ShowError(e.Message);
}
return;
}
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame
try
{
// read blocksize to find metadata block
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));
}
catch
{
}
IMp3FrameDecompressor decompressor = null;
try
{
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
readFullyStream.metaInt = metaInt;
do
{
if (bufferedWaveProvider != null && bufferedWaveProvider.BufferLength - bufferedWaveProvider.BufferedBytes < bufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame = null;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream, true);
}
catch (EndOfStreamException)
{
this.fullyDownloaded = true;
// reached the end of the MP3 file / stream
break;
}
catch (WebException)
{
// probably we have aborted download from the GUI thread
break;
}
if (decompressor == null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(waveFormat);
this.bufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
this.bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(20); // allow us to get well ahead of ourselves
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
bufferedWaveProvider.AddSamples(buffer, 0, decompressed);
}
} while (playbackState != StreamingPlaybackState.Stopped);
Debug.WriteLine("Exiting");
// was doing this in a finally block, but for some reason
// we are hanging on response stream .Dispose so never get there
decompressor.Dispose();
}
}
finally
{
if (decompressor != null)
{
decompressor.Dispose();
}
}
}
}
NAudio does not include an MP3 encoder. When I need to encode MP3 I use lame.exe. If you don't want to go via a file, lame.exe allows you to read from stdin and write to stdout, so if you redirect standard in and out on the process you can convert on the fly.