How do I save the result from GetProfileBinary into a smart pointer? - visual-c++

At the moment I have the following member variable in a class:
BYTE *m_pbyImportColumnMappings;
In one of the classes we attempt to read existing data from the registry, and if it is not present, we allocate it. So far, I have changed it like this:
void CImportOCLMAssignmentHistoryDlg::ReadSettings()
{
UINT uSize;
m_dwImportFlags = theApp.GetNumberSetting(theApp.GetActiveScheduleSection(_T("Options")),
_T("ImportFlags"), ImportAssignment::None);
theApp.GetProfileBinary(theApp.GetActiveScheduleSection(_T("Options")),
_T("ImportColumnMappings"), (LPBYTE*)&m_pbyImportColumnMappings, &uSize);
// Reset memory buffer (if required)
if (uSize != (sizeof(BYTE) * 15))
{
if (uSize > 0)
{
delete[] m_pbyImportColumnMappings;
m_pbyImportColumnMappings = nullptr;
}
m_pbyImportColumnMappings = new BYTE[15];
// Default values
const gsl::span column_mappings(m_pbyImportColumnMappings, 15);
std::fill(begin(column_mappings), end(column_mappings), -1);
/*
m_pbyImportColumnMappings[0] = -1;
m_pbyImportColumnMappings[1] = -1;
m_pbyImportColumnMappings[2] = -1;
m_pbyImportColumnMappings[3] = -1;
m_pbyImportColumnMappings[4] = -1;
m_pbyImportColumnMappings[5] = -1;
m_pbyImportColumnMappings[6] = -1;
m_pbyImportColumnMappings[7] = -1;
m_pbyImportColumnMappings[8] = -1;
m_pbyImportColumnMappings[9] = -1;
m_pbyImportColumnMappings[10] = -1;
m_pbyImportColumnMappings[11] = -1;
m_pbyImportColumnMappings[12] = -1;
m_pbyImportColumnMappings[13] = -1;
m_pbyImportColumnMappings[14] = -1;
*/
}
}
My initial change was to use a gsl::span to suppress several warnings about using pointer arithemetic. But I don't know how to turn m_pbyImportColumnMappings into a smart pointer, given the fact that we are attempting to initially populate it from GetProfileBinary.
If I could turn it into a smart pointer then I would not need to deallocate the memory when the class goes out of scope.
In a related answer this code was suggested:
theApp.GetProfileBinary(strSection, strEntry,
reinterpret_cast<LPBYTE*>(&pALI), &uBytesRead);
std::unique_ptr<BYTE[]> cleanup(reinterpret_cast<BYTE*>(pALI));
But, I am not sure how to apply that cleanup method given teh fact we are dealing with a member variable of the class as opposed to an isolated variable in a function.

For a cleaner code, consider using std::vector and a temporary buffer
std::vector<BYTE> m_mapping;
m_mapping.resize(15, -1);
...
UINT len = 0;
BYTE* temp = nullptr;
AfxGetApp()->GetProfileBinary(_T("setting"), _T("key"), &temp, &len);
std::unique_ptr<BYTE[]> cleanup(temp);
if (len == m_mapping.size() * sizeof(m_mapping[0]))
memcpy(m_mapping.data(), temp, len);
else
std::fill(m_mapping.begin(), m_mapping.end(), -1);
std::vector also has automatic cleanup and additional methods.
Otherwise, using std::unique_ptr to replace new/delete for this member data, can be a bit of a nightmare. Example:
m_mapping = nullptr;
GetProfileBinary("setting", "key", &m_mapping, &uSize);
if (uSize != (sizeof(BYTE) * 15))
{
{ std::unique_ptr<BYTE[]> cleanup(m_mapping); }
//delete memory immediately after exiting scope
//note the extra brackets
//allocate new memory and don't manage it anymore
m_mapping = std::make_unique<BYTE[]>(15).release();
if(m_mapping)
for (int i = 0; i < 15; i++) m_mapping[i] = -1;
}
Here we are not able to take advantage of std::unique_ptr memory management, it's only used to turn off warnings.
You don't need any casting here because it just happens that m_pbyImportColumnMappings is BYTE, and GetProfileBinary expects BYTE, it allocates memory using new BYTE

Related

U-boot does not silence its output

I have this uboot
VERSION = 2017
PATCHLEVEL = 03
I am trying to silent the console using the silent variable.I defined this #define CONFIG_SILENT_CONSOLE
So at boot time I am interrupting the console, and entering
setenv silent 1
save
reset
Now after reset, or power on reset I try again get console logs.After seeing env variables
printenv
I see my saved variable correctly in env varibles
silent=1
but still u-boot is not silent. I suspect this function is failing at checking for this env variable,
char *getenv(const char *name)
{
if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
ENTRY e, *ep;
WATCHDOG_RESET();
e.key = name;
e.data = NULL;
hsearch_r(e, FIND, &ep, &env_htab, 0); /*this function is maybe returning*/
return ep ? ep->data : NULL;
}
/* restricted capabilities before import */
if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
return NULL;
}
But what exactly is happening?
Is there something like before relocation time env variables and after relocation env variables because the function,
static void console_update_silent(void)
{
#ifdef CONFIG_SILENT_CONSOLE
if (getenv("silent") != NULL){
puts("silent");
gd->flags |= GD_FLG_SILENT;
}
else{
puts("Non silent");
gd->flags &= ~GD_FLG_SILENT;
}
#endif
}
/* Called before relocation - use serial functions */
int console_init_f(void)
{
gd->have_console = 1;
console_update_silent();
print_pre_console_buffer(PRE_CONSOLE_FLUSHPOINT1_SERIAL);
return 0;
}
console_init_f says its before relocation.
I have put some prints to see and always gets non silent, even if I have saved the silent variable,
I am using a sd card to boot(mmc), I don't have any debugger, so I
I tried printing default environment, as
env print default
## Error: "default" not defined
So there is not default environment too.
Any tips or help will make me understand.
P.S.
I explicitly defined silent in #define CONFIG_EXTRA_ENV_SETTINGS
Now u-boot is silent.
Doing a setenv silent should remove this from env variable, and I can see that its gone, but still on reboot my uboot is silent.
So something about environment variable is clearly mystery to me.
P.P.S
I come to see this code,
int getenv_f(const char *name, char *buf, unsigned len)
{
int i, nxt;
for (i = 0; env_get_char(i) != '\0'; i = nxt + 1) {
int val, n;
for (nxt = i; env_get_char(nxt) != '\0'; ++nxt) {
if (nxt >= CONFIG_ENV_SIZE)
return -1;
}
val = envmatch((uchar *)name, i);
if (val < 0)
continue;
/* found; copy out */
for (n = 0; n < len; ++n, ++buf) {
*buf = env_get_char(val++);
if (*buf == '\0')
return n;
}
if (n)
*--buf = '\0';
printf("env_buf [%d bytes] too small for value of \"%s\"\n",
len, name);
return n;
}
return -1;
}
Which is called by this
char *getenv(const char *name)
{
if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
ENTRY e, *ep;
WATCHDOG_RESET();
e.key = name;
e.data = NULL;
hsearch_r(e, FIND, &ep, &env_htab, 0);
return ep ? ep->data : NULL;
}
/* restricted capabilities before import */
if (getenv_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) > 0)
return (char *)(gd->env_buf);
return NULL;
}
From early board_init_f
this function
int env_init(void)
{
/* use default */
gd->env_addr = (ulong)&default_environment[0];
gd->env_valid = 1;
return 0;
}
makes env_addr to point always to read only memory of the code, and does not point to anything else such as where mmc environment are saved.
So this function always point to default_environment variable.
__weak uchar env_get_char_spec(int index)
{
return *((uchar *)(gd->env_addr + index));
}
static uchar env_get_char_init(int index)
{
/* if crc was bad, use the default environment */
if (gd->env_valid)
return env_get_char_spec(index);
else
return default_environment[index];
}
uchar env_get_char_memory(int index)
{
return *env_get_addr(index);
}
uchar env_get_char(int index)
{
/* if relocated to RAM */
if (gd->flags & GD_FLG_RELOC)
return env_get_char_memory(index);
else
return env_get_char_init(index);
}
So I conclude that inherently, u-boot code there is no possibility to point the mmc area where environments are stored.
Can anyone confirm this?

How to return few string from threads and concat it in C++/CLI

how to return few Strings from threads and link it to one String ?
I use CLI/C++, threads in windows forms. This code should divide message from user to n(nThreads) texts and in each thread should encipher message.
Finally it must concat all results to one.
Actually I did something like this:
public: ref class ThreadExample
{
public:
static String^ inputString;
static String^ outputString;
static array<String^>^ arrayOfThreads = gcnew array <String^>(nThreads);
static int iterator;
static void ThreadEncipher()
{
string input, output;
MarshalString(inputString, input);
output = CaesarCipher::encipher(input);
outputString = gcnew String(output.c_str());
arrayOfThreads[iterator] = outputString;
}
Function where I use threads:
array<String^>^ ThreadEncipherFuncCpp(int nThreads, string str2){
array<String^>^ arrayOfThreads = gcnew array <String^>(nThreads);
string loopSubstring;
messageLength = str2.length();
int numberOfSubstring = messageLength / nThreads;
int isModulo = messageLength % nThreads;
array<Thread^>^ xThread = gcnew array < Thread^ >(nThreads);
int j;
//loop dividing text to threads
for (int i = 0; i < nThreads; i++)
{
j = i;
if (i == 0 && numberOfSubstring != 0)
loopSubstring = str2.substr(0, numberOfSubstring);
else if ((i == nThreads - 1) && numberOfSubstring != 0){
if (isModulo != 0)
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring + isModulo);
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
}
else if (numberOfSubstring == 0){
loopSubstring = str2.substr(0, isModulo);
i = nThreads - 1;
}
else
loopSubstring = str2.substr(numberOfSubstring*i, numberOfSubstring);
xThread[i] = gcnew Thread(gcnew ThreadStart(&ThreadExample::ThreadEncipher));
}
auto start = chrono::system_clock::now();
for (int i = 0; i < nThreads; i++){
ThreadExample::iterator = i;
ThreadExample::inputString = gcnew String(loopSubstring.c_str());
xThread[i]->Start();
}
for (int i = 0; i < nThreads; i++){
xThread[i]->Join();
}
auto elapsed = chrono::system_clock::now() - start;
long long milliseconds = chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
cppTimer = milliseconds;
arrayOfThreads = ThreadExample::arrayOfThreads;
delete xThread;
return arrayOfThreads;
}
I'm going to take a guess here and say that the program ran without error, but your output was blank.
The reason the output is blank is because of the static class initializer. This is executed earlier than you think it is: As soon as you reference the class in any way, the static initializer runs. Therefore, when you try to execute ThreadExample::inputString = "Some example text. Some example text2.";, the static class initializer has already run, and your array of threads is set.
To fix this, move that code out of the static initializer, and into the method where you create the threads.
Also, a more general note on C++/CLI: If you're trying to learn C++, please don't use C++/CLI. C++/CLI is not the same thing as C++. C++/CLI has all the complexities of C++, all the complexities of C#, and some complexities of its own thrown in for good measure. It should be used when it's needed to interface .Net code to C++ code, not as a primary development language.

Error when reading from Linux FIFO

In the embedded application I'm working on we have a serial port abstraction, and I'm currently working on a simulated variant of said abstraction to use when you are not running on the 'real' hardware. I'm using FIFO files for this, as you can then plug in whathever software you want to communicate with the actual application but I'm having trouble with the "read" function, which flags that you gave it an invalid fd. Though I have used debugging tools to verify that the fd passed to it is the same as has been opened earlier so it should be valid. I cannot find any cause for this problem.
FIFO files are opened through this function:
int createOpenFifo(const std::string& path, int flags)
{
int fd = open(path.c_str(), flags);
if (fd < 0)
{
mkfifo(path.c_str(), 0777);
fd = open(path.c_str(), flags);
if (fd < 0)
{
return -1;
}
}
return fd;
}
And the FIFOs are then written to using the following function:
int write_serial(handle_t handle, size_t length, const uint8_t* pData)
{
SerialFifoData* data = static_cast<SerialFifoData*>(handle);
size_t written = 0;
while (written < length)
{
int result = write(data->writeFd, pData + written, length - written);
if (result < 0)
{
return -1;
}
written += result;
}
return 0;
}
And finally read from using this function:
int read_serial(handle_t handle, size_t buffer_size, uint8_t* pBuffer, size_t* bytes_read)
{
SerialFifoData* data = static_cast<SerialFifoData*>(handle);
int return_val = read(data->readFd, pBuffer, buffer_size);
if (return_val < 0)
{
if (errno == EAGAIN || errno == EWOULDBLOCK) // Non-blocking, no data
// which flag is raised
// varies between POSIX
// implementations
{
*bytes_read = 0;
return -2;
}
return -1;
}
*bytes_read = return_val;
return 0;
}
I have verified that each function recieves correct input, and the read and write calls are nearly identical to those used for the actual serial port code (the only difference is how the FD is extracted from the handle) where they work just fine.

Invalid read and write of size in valgrind

I have invalid read of size in the following functions using valgrind. I'm not exactly sure why but if any of you can help me that would be greatly appreciated! From what I can tell it runs okay but there are still some errors that I'm not catching that may even deal with memory allocation and deallocation. Please help!
//alternate constructor that allows for setting of the inital value of the string
MyString::MyString(const char *message)
{
int counter(0);
while(message[counter] != '\0')
{
counter++;
}
Size = counter;
**String = new char [Size];**
for(int i=0; i < Size; i++)
String[i] = message[i];
}
istream& operator>>(istream& input, MyString& rhs)
{
char* t;
int size(256);
t = new char[size];
input.getline(t,size);
**rhs = MyString(t);**
delete [] t;
return input;
}
/*Assignment operator (=) which will copy the source string into the destination string. Note that size of the destination needs to be adjusted to be the same as the source.
*/
MyString& MyString::operator=(const MyString& rhs)
{
if(this != &rhs)
{
delete [] String;
**String = new char[rhs.Size+1];**
Size = rhs.Size;
for(int i = 0; i < Size; i++)
{
** String[i] = rhs.String[i];**
}
}
return *this;
}
Any suggestions?? (All of the problem lines have **)
One thing I see is that your copy constructor doesn't allocate space for \0 and doesn't copy it. Neither does the assignment operator.. Or, if you don't store terminating zero, then why are you looking for it?
and the two implementations differ, why the inconsistency (Size vs counter)?
"From what I can tell it runs okay" - it's called undefined behaviour, or in this case: luck - or, if you like me, and like to catch bugs: a misfortune.

Unzipping archive on Windows 8

I have previously used MiniZip (zlib wrapper) to unzip archives. MiniZip cannot be used for Metro applications as it uses deprecated APIs in "iowin32.c" -- CreateFile() and SetFilePointer().
I thought that would be an easy fix and created "iowinrt.c" with CreateFile() and SetFilePointer() replaced with CreateFile2() and SetFilePointerEx(). While this way I obtained a version of MiniZip that uses only approved Win8 APIs, it still turned out to be useless -- I forgot about sandboxing. If I pick a file using FileOpenPicker() and pass its path to my modified MiniZip I still cannot open it -- CreateFile2() will fail with "Access is denied." message.
So it appears that old C API for file access if now mostly useless; it is my understanding that in order to fix this I would need to reimplement my "iowinrt" in C++/CX using the new async file access. Are there any other options? I think I saw somewhere that WinRT does have compress/uncompress functionality but that it only works on individual files, not archives.
Additional requirements it that I need this to work in memory.
For a moment I thought I had a solution via .NET Framework 4.5:
I found this piece of info about how to create .NET classes that can be used from C++/CX:
http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/3ff383d0-0c9f-4a30-8987-ff2b23957f01
.NET Framework 4.5 contains ZipArchive and ZipArchiveEntry classes in System.IO.Compression:
http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchive%28v=vs.110%29.aspx#Y0
http://msdn.microsoft.com/en-us/library/system.io.compression.ziparchiveentry%28v=vs.110%29.aspx#Y0
I thought I could create C# Metro Class Library with WinMD Output type exposing ZipArchive and ZipArchiveEntry then use that in my C++/CX project. However, even if it worked it would not work in-memory; it appears that ZipArchive and ZipArchiveEntry work only with files.
Got reading from archive working. Explanation and code below but really just a hack at this point, to see if it's possible at all. I just kept modifying things until I got something working; this is just an example of what works and by no means a production quality code (it's not re-entrant for start). There are undoubtedly many things that are bad/unnecessary/wtf so feel free to use comments to help with clean up.
As mentioned previously, it is no longer enough to pass path to the library -- unless file is in one of KnownFolders (documents, home, media, music, pictures, removable or videos) you end up with "access is denied" message. Instead, library must be able to accept StorageFile^, as returned from FileOpenPicker. At least I haven't found any other way to do it, maybe someone knows better?
MiniZip provides Windows filesystem access layer for zlib via iowin32.h/.c. This still works in desktop mode for old-style apps, but does not work for Metro apps as it uses deprecated APIs and relies on paths. To get MiniZip going on Windows 8, a complete rewrite of iowin32 is required.
To get things working again, first thing was to find a way to pass StorageFile^ all the way down to iowinrt (Windows 8 replacement for iowin32). Fortunately, that was not a problem as MiniZip provides two styles of open file functions -- ones that accept pointer to char, and the others accepting pointer to void. Since ^ is still just a pointer, casting StorageFile^ to void* and than back to StorageFile^ works fine.
Now that I was able to pass StorageFile^ to my new iowinrt, the next problem was how to make new async C++ file access API work with Zlib. In order to support very old C compilers, Zlib is written with old K&R style C. VisualStudio compiler will refuse to compile this as C++, it has to be compiled as C, and new iowinrt must be compiled as C++ of course -- keep that in mind when creating your project. Other things to note about VS project is that I did it as Visual C++ Windows Metro style Static Library although DLL should also work but then you must also define macro to export MiniZip API (I haven't tried this, don't know which macro you have to use). I think I also had to set "Consume Windows Runtime Extension" (/ZW), set "Not Using Precompiled Headers" and add _CRT_SECURE_NO_WARNINGS and _CRT_NONSTDC_NO_WARNINGS to Preprocessor Definitions.
As for iowinrt itself, I've split it in two files. One holds two sealed ref classes -- reader and writer objects; they accept StorageFile^. Reader implements Read, Tell, SeekFromBeginning, SeekFromCurrent and SeekFromEnd (the reason for 3 Seek methods is because ref sealed classes have to stick with RT types and that apparently excludes enums so I just took the easy route). Writer implements just Write at the moment, haven't used it yet.
This is FileReader code:
#include "pch.h"
#include "FileAccess.h" // FileReader and FileWriter
using namespace Concurrency;
using namespace Windows::Security::Cryptography;
using namespace CFileAccess;
FileReader::FileReader(StorageFile^ archive)
{
if (nullptr != archive)
{
create_task(archive->OpenReadAsync()).then([this](IRandomAccessStreamWithContentType^ archiveStream)
{
if (nullptr != archiveStream)
{
_readStream = archiveStream;
}
}).wait();
}
} // end of constructor
int32 FileReader::Read(WriteOnlyArray<byte>^ fileData)
{
int32 bytesRead = 0;
if ((nullptr != _readStream) && (fileData->Length > 0))
{
try
{
auto inputStreamReader = ref new DataReader(_readStream);
create_task(inputStreamReader->LoadAsync(fileData->Length)).then([&](task<unsigned int> dataRead)
{
try
{
bytesRead = dataRead.get();
if (bytesRead)
{
inputStreamReader->ReadBytes(fileData);
}
}
catch (Exception^ e)
{
bytesRead = -1;
}
inputStreamReader->DetachStream();
}).wait();
}
catch (Exception^ e)
{
bytesRead = -1;
}
}
return (bytesRead);
} // end of method Read()
int64 FileReader::Tell(void)
{
int64 ret = -1;
if (nullptr != _readStream)
{
ret = _readStream->Position;
}
return (ret);
} // end of method Tell()
int64 FileReader::SeekFromBeginning(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && (offset < _readStream->Size))
{
_readStream->Seek(offset);
ret = 0;
}
return (ret);
} // end of method SeekFromBeginning()
int64 FileReader::SeekFromCurrent(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && ((_readStream->Position + offset) < _readStream->Size))
{
_readStream->Seek(_readStream->Position + offset);
ret = 0;
}
return (ret);
} // end of method SeekFromCurrent()
int64 FileReader::SeekFromEnd(uint64 offset)
{
int64 ret = -1;
if ((nullptr != _readStream) && ((_readStream->Size - offset) >= 0))
{
_readStream->Seek(_readStream->Size - offset);
ret = 0;
}
return (ret);
} // end of method SeekFromEnd()
iowinrt sits between MiniZip and FileReader (and FileWriter). It's too long to give everything here but this should be sufficient to reconstruct the rest since it's mostly just more of the same with different function names, plus a bunch of fill_winRT_filefuncxxx() which are obvious:
#include "zlib.h"
#include "ioapi.h"
#include "iowinrt.h"
#include "FileAccess.h"
using namespace Windows::Security::Cryptography;
using namespace Platform;
using namespace CFileAccess;
static FileReader^ g_fileReader = nullptr;
static FileWriter^ g_fileWriter = nullptr;
static StorageFile^ g_storageFile = nullptr;
[...]
static voidpf winRT_translate_open_mode(int mode)
{
if (nullptr != g_storageFile)
{
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
{
g_fileWriter = nullptr;
g_fileReader = ref new FileReader(g_storageFile);
}
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
{
g_fileReader = nullptr;
g_fileWriter = ref new FileWriter(g_storageFile);
}
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
{
g_fileReader = nullptr;
g_fileWriter = ref new FileWriter(g_storageFile);
}
}
return (nullptr != g_fileReader ? reinterpret_cast<voidpf>(g_fileReader) : reinterpret_cast<voidpf>(g_fileWriter));
}
voidpf ZCALLBACK winRT_open64_file_func (voidpf opaque,const void* storageFile,int mode)
{
g_storageFile = reinterpret_cast<StorageFile^>(const_cast<void*>(storageFile));
return (winRT_translate_open_mode(mode));
}
[...]
Long ZCALLBACK winRT_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size)
{
uLong bytesRead = 0;
if (nullptr != g_fileReader)
{
auto fileData = ref new Platform::Array<byte>(size);
bytesRead = g_fileReader->Read(fileData);
memcpy(buf, fileData->Data, fileData->Length);
}
return (bytesRead);
}
uLong ZCALLBACK winRT_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size)
{
uLong bytesWritten = 0;
if (nullptr != g_fileWriter)
{
auto bytes = ref new Array<uint8>(reinterpret_cast<uint8*>(const_cast<void*>(buf)), size);
IBuffer ^writeBuffer = CryptographicBuffer::CreateFromByteArray(bytes);
bytesWritten = g_fileWriter->Write(writeBuffer);
}
return (bytesWritten);
}
long ZCALLBACK winRT_tell_file_func (voidpf opaque,voidpf stream)
{
long long ret = 0;
if (nullptr != g_fileReader)
{
ret = g_fileReader->Tell();
}
return (static_cast<long>(ret));
}
ZPOS64_T ZCALLBACK winRT_tell64_file_func (voidpf opaque, voidpf stream)
{
ZPOS64_T ret = 0;
if (nullptr != g_fileReader)
{
ret = g_fileReader->Tell();
}
return (ret);
}
[...]
long ZCALLBACK winRT_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin)
{
long long ret = -1;
if (nullptr != g_fileReader)
{
switch (origin)
{
case ZLIB_FILEFUNC_SEEK_CUR :
ret = g_fileReader->SeekFromCurrent(offset);
break;
case ZLIB_FILEFUNC_SEEK_END :
ret = g_fileReader->SeekFromEnd(offset);
break;
case ZLIB_FILEFUNC_SEEK_SET :
ret = g_fileReader->SeekFromBeginning(offset);
break;
default:
// should never happen!
ret = -1;
break;
}
}
return (static_cast<long>(ret));
}
int ZCALLBACK winRT_close_file_func (voidpf opaque, voidpf stream)
{
g_fileWriter = nullptr;
g_fileReader = nullptr;
return (0);
}
int ZCALLBACK winRT_error_file_func (voidpf opaque,voidpf stream)
{
/// #todo Get errors from FileAccess
return (0);
}
This is enough to get MiniZip going (at least for reading) but you have to take care how you call MiniZip functions -- since Metro is all about async and blocking UI thread will end up with exception, you must wrap access in tasks:
FileOpenPicker^ openPicker = ref new FileOpenPicker();
openPicker->ViewMode = PickerViewMode::List;
openPicker->SuggestedStartLocation = PickerLocationId::ComputerFolder;
openPicker->FileTypeFilter->Append(".zip");
task<IVectorView<StorageFile^>^>(openPicker->PickMultipleFilesAsync()).then([this](IVectorView<StorageFile^>^ files)
{
if (files->Size > 0)
{
std::for_each(begin(files), end(files), [this](StorageFile ^file)
{ // open selected zip archives
create_task([this, file]()
{
OpenArchive(file);
[...]
});
});
}
else
{
rootPage->NotifyUserBackgroundThread("No files were returned.", NotifyType::ErrorMessage);
}
});
[...]
bool OpenArchive(StorageFile^ archive)
{
bool isArchiveOpened = false;
if (nullptr != archive)
{ // open ZIP archive
zlib_filefunc64_def ffunc;
fill_winRT_filefunc64(&ffunc);
unzFile archiveObject = NULL;
create_task([this, &ffunc, archive]()
{
archiveObject = unzOpen2_64(reinterpret_cast<const void*>(archive), &ffunc);
}).wait();
if (NULL != archiveObject)
{
[...]

Resources