I am searching how to open archive from memory buffer using minizip.
I found ioapi_mem_c.zip from their page http://www.winimage.com/zLibDll/minizip.html.
I can't understand how to use it. Can some one give me an example?
I solved my problem for unziping:
I added this function to unzip.c
extern unzFile ZEXPORT unzOpenBuffer (const void* buffer, uLong size)
{
char path[16] = {0};
zlib_filefunc64_32_def memory_file;
uLong base = (uLong)buffer;
sprintf(path, "%x+%x", base, size);
fill_memory_filefunc64_32(&memory_file);
return unzOpenInternal(path, &memory_file, 0);
}
And made some changes in ioapi_mem.c:
void fill_memory_filefunc64_32 (pzlib_filefunc_def)
zlib_filefunc64_32_def* pzlib_filefunc_def;
{
pzlib_filefunc_def->zopen32_file = fopen_mem_func;
pzlib_filefunc_def->zfile_func64.zopen64_file = fopen_mem_func;
pzlib_filefunc_def->zfile_func64.zread_file = fread_mem_func;
pzlib_filefunc_def->zfile_func64.zwrite_file = fwrite_mem_func;
pzlib_filefunc_def->ztell32_file = ftell_mem_func;
pzlib_filefunc_def->zseek32_file = fseek_mem_func;
pzlib_filefunc_def->zfile_func64.zseek64_file = NULL;
pzlib_filefunc_def->zfile_func64.zclose_file = fclose_mem_func;
pzlib_filefunc_def->zfile_func64.zerror_file = ferror_mem_func;
pzlib_filefunc_def->zfile_func64.opaque = NULL;
}
I hope this will help someone who will have the same problem.
And Here is simple class implementation how to use it:
void ZipArchiveImpl::OpenArchive()
{
ASSERT(!mInited, "Already opened.");
if ((mFileMode == FM_READ))
{
if (mArchiveName.size() == 0)
{
u32 sz = mFile->GetFileSize();
mUnzBlock.Resize(sz);
mFile->SetPosition(0);
mFile->Read(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());
mUnzHandle = unzOpenBuffer(mUnzBlock.Data(), mUnzBlock.GetSizeInBytes());
}
else
{
mUnzHandle = unzOpen(mArchiveName.c_str());
}
if (!mUnzHandle) return;
FillMap();
}
else if (mFileMode == FM_WRITE)
{
ASSERT0(mArchiveName.size());
mZipHandle = zipOpen(mArchiveName.c_str(), 0);
if (!mZipHandle) return;
}
mInited = true;
}
IFile* ZipArchiveImpl::OpenRead(const std::string& name)
{
if (IsExist(name))
{
ZipFileInfo info = mFileMap.find(name)->second;
MemoryBlock block(1);
block.Resize(info.uncompressedSize);
int res = unzGoToFilePos(mUnzHandle, &info.filePosInfo);
if (UNZ_OK != res)
{
return false;
}
// open the current file with optional password
if (mArchivePassword != "")
{
res = unzOpenCurrentFilePassword(info.zipFileHandle, mArchivePassword.c_str());
}
else
{
res = unzOpenCurrentFile(info.zipFileHandle);
}
if (UNZ_OK != res)
{
return false;
}
// read uncompressed data
int readResult = unzReadCurrentFile(info.zipFileHandle, block.Data(), info.uncompressedSize);
// close the file
res = unzCloseCurrentFile(info.zipFileHandle);
if (UNZ_OK != res)
{
return false;
}
if (info.uncompressedSize == readResult)
{
return ROBE_NEW MemoryFile(block.Data(), info.uncompressedSize);
}
else
{
return NULL;
}
}
else
{
return NULL;
}
}
IFile* ZipArchiveImpl::OpenRead(u32 id)
{
ASSERT0(mFileNames.size() > id);
if (IsExist(mFileNames[id]))
{
return OpenRead(mFileNames[id]);
}
else
{
return NULL;
}
}
void ZipArchiveImpl::FillMap()
{
s32 walkRes = unzGoToFirstFile(mUnzHandle);
unz_file_info info;
while (UNZ_OK == walkRes)
{
// get info about current file
char currentFileName[512];
s32 fileInfoRes = unzGetCurrentFileInfo(mUnzHandle, &info, currentFileName, sizeof(currentFileName), 0, 0, 0, 0);
std::string name = std::string(currentFileName);
mFileNames.push_back(name);
InitInfo(name, &info);
walkRes = unzGoToNextFile(mUnzHandle);
}
OpenRead(0);
if (UNZ_END_OF_LIST_OF_FILE != walkRes)
{
}
}
void ZipArchiveImpl::InitInfo(const std::string& name, unz_file_info* info)
{
ZipFileInfo zfi;
mFileMap.insert(std::pair<std::string, ZipFileInfo>(name, zfi));
mFileMap[name].zipFileHandle = mUnzHandle;
int res = unzGetFilePos(mFileMap[name].zipFileHandle, &mFileMap[name].filePosInfo);
mFileMap[name].uncompressedSize = info->uncompressed_size;
char lastsymbol = name[name.size() - 1];
if (lastsymbol == '/' || lastsymbol == '\\')
{
mFileMap[name].type = ZFT_DIR;
}
else
{
mFileMap[name].type = ZFT_FILE;
}
}
ZipArchiveImpl::~ZipArchiveImpl()
{
if (mInited)
{
if (mUnzHandle) unzClose(mUnzHandle);
if (mZipHandle) zipClose(mZipHandle, 0);
}
}
bool ZipArchiveImpl::IsExist(const std::string& name)
{
return (mFileMap.find(name) != mFileMap.end());
}
void ZipArchiveImpl::SaveFileToZip(const std::string& path, IFile* file)
{
const u32 DefaultFileAttribute = 32;
MemoryBlock block(1);
block.Resize(file->GetFileSize());
file->Read(block.Data(), block.GetSizeInBytes());
zip_fileinfo zinfo;
memset(&zinfo, 0, sizeof(zinfo));
zinfo.internal_fa = 0;
zinfo.external_fa = DefaultFileAttribute;
::boost::posix_time::ptime pt = ::boost::posix_time::from_time_t(time(0));
std::tm ptm = ::boost::posix_time::to_tm(pt);
zinfo.dosDate = 0;
zinfo.tmz_date.tm_year = ptm.tm_year;
zinfo.tmz_date.tm_mon = ptm.tm_mon;
zinfo.tmz_date.tm_mday = ptm.tm_mday;
zinfo.tmz_date.tm_hour = ptm.tm_hour;
zinfo.tmz_date.tm_min = ptm.tm_min;
zinfo.tmz_date.tm_sec = ptm.tm_sec;
zipOpenNewFileInZip(mZipHandle, path.c_str(), &zinfo, 0, 0, 0, 0, 0, Z_DEFLATED, Z_BEST_SPEED);
zipWriteInFileInZip(mZipHandle, block.Data(), block.GetSizeInBytes());
zipCloseFileInZip(mZipHandle);
}
unsigned long ZipArchiveImpl::GetFileAttributes(const std::string& filePath)
{
unsigned long attrib = 0;
#ifdef WIN32
attrib = ::GetFileAttributes(filePath.c_str());
#else
struct stat path_stat;
if (::stat(filePath.c_str(), &path_stat) == 0)
{
attrib = path_stat.st_mode;
}
#endif
return attrib;
}
added this function to unzip.c
extern unzFile ZEXPORT unzOpenBuffer(const void* buffer, uLong size)
{
zlib_filefunc_def filefunc32 = { 0 };
ourmemory_t *punzmem = (ourmemory_t*)malloc(sizeof(ourmemory_t));
punzmem->size = size;
punzmem->base = (char *)malloc(punzmem->size);
memcpy(punzmem->base, buffer, punzmem->size);
punzmem->grow = 0;
punzmem->cur_offset = 0;
punzmem->limit = 0;
fill_memory_filefunc(&filefunc32, punzmem);
return unzOpen2(NULL, &filefunc32);
}
Looking at the code in the link, there is no obvious way to pass a memory buffer. Save your memory buffer as a file, unzip it.
Or you could implement your own zlib_filefunc_def variant that operates on a lump of memory instead of a file. I don't think that is very hard to do.
Checkout the nmoinvaz fork of minizip: To unzip from a zip file in memory use fill_memory_filefunc and supply a proper ourmemory_t structure
zlib_filefunc_def filefunc32 = {0};
ourmemory_t unzmem = {0};
unzmem.size = bufsize;
unzmem.base = (char *)malloc(unzmem.size);
memcpy(unzmem.base, buffer, unzmem.size);
fill_memory_filefunc(&filefunc32, &unzmem);
unzOpen2("__notused__", &filefunc32);
Related
I know that the main problem comes from recursively calling FindFile(). With recursively calling this function, my i becomes 0. But I don't understand how I can fix this problem.
If possible, give advice on how to fix this bug without completely reworking all the functions below. Or provide a link where you can read about the correct initialization of icons in CListViewCtrl.
void Finder::FindFile(CString szPath)
{
HIMAGELIST hSmall{};
CFindFile F;
CString S = szPath + TEXT("\\*.*");
int i = 0;
BOOL bFlag = F.FindFile(S);
if (!bFlag)
{
MessageBox(TEXT("Error"), TEXT("File not found"), 0);
}
else
{
do
{
if (F.IsDots() == TRUE)
{
continue;
}
else
{
if (F.IsDirectory() == TRUE)
{
View_List(F.GetFileName(), i, F.GetFilePath());
i++;
FindFile(F.GetFilePath());
}
else
{
View_List(F.GetFileName(), i, F.GetFilePath());
i++;
}
}
} while (F.FindNextFileW());
F.Close();
InitListViewImage(i, S);
}
}
void Finder::View_List(CString name, int i, CString path)
{
CString nameWithoutEx=std::get<0>(Split(name));
CString extention= std::get<1>(Split(name));
lvItem.mask = LVIF_IMAGE | LVIF_TEXT;
lvItem.state = 0;
lvItem.stateMask = 0;
lvItem.iItem = i;
lvItem.iImage = i;
lvItem.iSubItem = 0;
lvItem.pszText = (LPWSTR)nameWithoutEx.GetString();
lvItem.cchTextMax = nameWithoutEx.GetLength();
myListView.InsertItem(&lvItem);
myListView.SetItemText(i, 1, extention.GetString());
myListView.SetItemText(i, 2, path.GetString());
}
std::tuple<CString, CString> Finder::Split(CString buf)
{
CString tmp = buf;
if (buf.Find(TEXT(".")) == -1)
{
return { buf.GetString(),TEXT("Directory") };
}
else
{
int index = buf.Find(TEXT("."))+1;
if (buf.Find(TEXT("."),index) != -1)
{
while (buf.Find(TEXT("."), index) != -1)
{
index = buf.Find(TEXT("."), index)+1;
}
}
buf.Delete(index-1, buf.GetLength());
tmp.Delete(0, index-1);
return{ buf.GetString(),tmp.GetString() };
}
}
BOOL Finder::InitListViewImage(int size, CString path)
{
CFindFile F;
HIMAGELIST hSmall;
SHFILEINFO lp{};
hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), ILC_MASK | ILC_COLOR32, size, 1);
bool hFind = F.FindFile(path);
if (!hFind)
{
MessageBox(TEXT("Error"), TEXT("File not found"), MB_OK | MB_ICONWARNING);
}
else
{
do
{
if (F.IsDots() == TRUE)
{
continue;
}
DWORD num = GetFileAttributesW(F.GetFilePath());
SHGetFileInfoW(F.GetFilePath(), num, &lp, sizeof(lp), SHGFI_SYSICONINDEX | SHGFI_ICON | SHGFI_USEFILEATTRIBUTES);
ImageList_AddIcon(hSmall, lp.hIcon);
DestroyIcon(lp.hIcon);
} while (F.FindNextFileW());
F.Close();
}
myListView.SetImageList(hSmall, 1);
return TRUE;
}
You need to pass the value of i as a reference to FindFile so that when you call it recursively the value continues to increment.
void Finder::FindFile(CString szPath, int& i)
{
HIMAGELIST hSmall{};
CFindFile F;
CString S = szPath + TEXT("\\*.*");
// int i = 0; <-- not declared here, as it is now an argument
BOOL bFlag = F.FindFile(S);
if (!bFlag)
{
MessageBox(TEXT("Error"), TEXT("File not found"), 0);
}
else
{
do
{
if (F.IsDots() == TRUE)
{
continue;
}
else
{
if (F.IsDirectory() == TRUE)
{
View_List(F.GetFileName(), i, F.GetFilePath());
i++;
FindFile(F.GetFilePath(), i); // <-- pass i to the recursive function
}
else
{
View_List(F.GetFileName(), i, F.GetFilePath());
i++;
}
}
} while (F.FindNextFileW());
F.Close();
InitListViewImage(i, S);
}
}
When you call FindFile from your main function or wherever, you need to give it a variable to use as the starting point, e.g.
main()
{
int i = 0;
FindFile("C:\", i);
}
I'm currently trying to develop snmpManager in my embedded device(linux OS). This device should communicate with another device's snmpAgent. Well, my code working good for snmpV2c also my snmp packets show in wireshark pcap. But when i try snmpV3 packets snmp_synch_response(session, requestPdu, &responsePdu) func return STAT_ERROR Btw snmpV2c was returning STAT_SUCCESS My code is shown in below, i created snmp session for v2 and v3.
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
static const char* v3_passphrase = "blablabl";
session.retries = 2;
session.timeout = 1000000;
session.engineBoots = 0;
session.engineTime = 0;
QString engineID = "0000000c000000007f000001";
session.contextEngineID = reinterpret_cast<uchar*>(strdup(engineID.toAscii()));
qDebug()<<"contextEngineID:"<<session.contextEngineID;
/*memory allocated by strdup() will be freed by calling snmp_close() */
if(SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv2c)
{
session.version = SNMP_VERSION_2c;
const char *str;
QString path = "user";
QByteArray ba;
ba = path.toLatin1();
str = ba.data();
session.community = const_cast<unsigned char*>(reinterpret_cast<const unsigned char *>(str));
session.community_len = path.length();
session.retries = 2;
session.timeout = 1000000;
}
else if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3)
{
session.version = SNMP_VERSION_3;
session.securityName = strdup("blabl");
session.securityNameLen = strlen(session.securityName);
session.securityModel = USM_SEC_MODEL_NUMBER;
session.securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
session.securityAuthProto = usmHMACMD5AuthProtocol;
// session.securityAuthProtoLen = sizeof (usmHMACMD5AuthProtocol) / sizeof (oid);
session.securityAuthProtoLen = USM_AUTH_PROTO_MD5_LEN;
session.securityPrivProto = usmNoPrivProtocol;
session.securityPrivProtoLen = USM_PRIV_PROTO_NOPRIV_LEN;
session.securityAuthKeyLen =USM_AUTH_KU_LEN;
if (generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen) != SNMPERR_SUCCESS)
{
qWarning()<<"ERROR KODU"<<generate_Ku(session.securityAuthProto,session.securityAuthProtoLen,(u_char *) (v3_passphrase),
strlen(v3_passphrase),session.securityAuthKey,
&session.securityAuthKeyLen);
snmp_log(LOG_ERR,"Error generating Ku from authentication pass phrase. \n");
exit(1);
}
}
struct snmp_session* openedSession = snmp_open(&session);
if(openedSession == nullptr)
{
snmp_sess_perror(reinterpret_cast<const char*>("No Ack!"), openedSession);
qWarning()<<"Error while Session opening! FILE:"<<__FILE__<<"LINE:"<<__LINE__;
}
else
qDebug()<<"creating session is succeed!";
return openedSession;
}
Session is creating successfully. no problem so far. Let's continue, then i create pdu like shown below,
snmp_pdu *snmptypes::fCreatePDU(tsPDUvariables PDUvariables)
{
// qDebug()<<"nrepeaters"<<PDUvariables.nrepeaters;
// qDebug()<<"mrepeaters"<<PDUvariables.mrepetitions;
qDebug()<<"setParam"<<PDUvariables.setParam;
qDebug()<<"dataType"<<PDUvariables.dataType;
struct snmp_pdu* requestPdu;
oid requestOid[MAX_OID_LEN];
size_t requestOidLength = MAX_OID_LEN;
snmp_parse_oid(static_cast<const char*>(PDUvariables.OID.toAscii()), requestOid, &requestOidLength);
switch (PDUvariables.msgType) {
case snmpGet:
requestPdu = snmp_pdu_create(SNMP_MSG_GET);
if (SnmpMainWidget::activeWaveForm == SnmpMainWidget::snmpv3){
requestPdu->version = SNMP_VERSION_3;
requestPdu->securityName = strdup("user");
requestPdu->securityNameLen = strlen(requestPdu->securityName);
requestPdu->securityLevel = SNMP_SEC_LEVEL_AUTHNOPRIV;
requestPdu->securityModel = USM_SEC_MODEL_NUMBER;
}
snmp_add_null_var(requestPdu, requestOid, requestOidLength);
break;
//there are some other case like set,getbulk but don't need to focus these.get enough for now.
}
qDebug()<<"creating PDU is succeed!";
return requestPdu;
}
Finally I'm using snmpget func. for send snmp packet to dedicated IP;
Problem occure right here, snmpv2 snmpStatus return success but snmpv3 reutn error. There for snmpv3 packet doesn't appear on wireshark and also doesn't send. I cant understand what am i wrong in V3 while V2 was working well.
bool snmptypes::fSnmpGet(QString IP,QString OID)
{
const char PACKET_HEADER_BYTE = 4;//4Byte = SOH + len/256 + len%256 + EOH
struct snmp_session* session = fCreateSession(IP);
tsPDUvariables PDUvariables;
PDUvariables.OID = OID;
PDUvariables.msgType = snmpGet;
struct snmp_pdu* requestPdu = fCreatePDU(PDUvariables);
qDebug()<<"PDUvariables.msgType"<<PDUvariables.msgType;
qDebug()<<"PDUvariables.dataType"<<PDUvariables.dataType;
qDebug()<<"PDUvariables.OID"<<PDUvariables.OID;
qDebug()<<"PDUvariables.setParam"<<PDUvariables.setParam;
struct snmp_pdu* responsePdu = nullptr;
if(requestPdu != nullptr && session != nullptr)
{
int snmpStatus = snmp_synch_response(session, requestPdu, &responsePdu);
qDebug()<<"snmpStatus"<<snmpStatus;
qDebug()<<"requestStatus::errStat"<<requestPdu->errstat;
qDebug()<<"session->s_errno"<<session->s_errno;
if(snmpStatus == STAT_SUCCESS)
{
if( responsePdu->errstat == SNMP_ERR_NOERROR and responsePdu->errstat == SNMP_ERR_NOERROR)
{
/* SUCCESS: Print the result variables */
struct variable_list *snmpVariables;
for(snmpVariables = responsePdu->variables; snmpVariables; snmpVariables = snmpVariables->next_variable)
{ qDebug()<<"fSnmpGet"<<__LINE__;
print_variable(snmpVariables->name, snmpVariables->name_length, snmpVariables);
}
for(snmpVariables = responsePdu->variables; snmpVariables != nullptr; snmpVariables = snmpVariables->next_variable)
{
QString strOID;
for(size_t i =0; i<snmpVariables->name_length;i++)
{
qDebug()<<"snmpVariables->name[i]"<<snmpVariables->name[i];
strOID.append(".");
strOID.append(QString::number( snmpVariables->name[i]));
}
qDebug()<<"strOID"<<strOID;
unsigned int OIDLen = static_cast<unsigned int> (strOID.length());
qDebug()<<"OID_Length:"<< static_cast<unsigned int> (OIDLen);
unsigned int paramLen = static_cast<unsigned int> (snmpVariables->val_len);
qDebug()<<"paramLen"<<paramLen;
unsigned int txDataLen = 5+OIDLen + paramLen;
qDebug()<<"txDataLen"<<txDataLen;
int totalTxDataLen = txDataLen+PACKET_HEADER_BYTE;
unsigned char *outMessBuff = static_cast<unsigned char *>(malloc(totalTxDataLen));
unsigned char *dataBuff = static_cast<unsigned char *>(malloc(txDataLen));
dataBuff[0] = snmpReqResponse;
dataBuff[1] = static_cast<unsigned char>(OIDLen/256 );
dataBuff[2] = static_cast<unsigned char>(OIDLen%256) ;
dataBuff[3] = static_cast<unsigned char>(paramLen/256) ;
dataBuff[4] = static_cast<unsigned char>(paramLen%256 );
if(OIDLen > 0)
{
memcpy(dataBuff+5,strOID.toAscii(),OIDLen);
}
if(paramLen > 0)
{
memcpy(dataBuff+5+OIDLen,snmpVariables->val.string,paramLen);
}
totalTxDataLen = SnmpMainWidget::IPC.prepareIPCmessage(outMessBuff, dataBuff, static_cast<int>(txDataLen));
SnmpMainWidget::IPC.sendIpcMessageToQt(reinterpret_cast<const char *>(outMessBuff),static_cast<unsigned int>(totalTxDataLen)); // reinterpret_cast bit of dangerous should be good test !!
SnmpMainWidget::IPC.PrintPacketInHex("SNMP-->QT :",outMessBuff, static_cast<unsigned int>(totalTxDataLen));
free(dataBuff);
free(outMessBuff);
}
}
}
else
{
if(snmpStatus == STAT_SUCCESS)
{
fprintf(stderr, "Error in packet\nReason: %s\n", snmp_errstring(responsePdu->errstat));
}
else if(snmpStatus == STAT_TIMEOUT)
{
fprintf(stderr, "Timeout: No response from %s.\n", session->peername);
}
else
{
printf("snmp get requestPdu->command: %d\n", requestPdu->command);
printf("snmp get errstat: %s\n", snmp_errstring(requestPdu->errstat));
printf("snmp get errindex: %s\n", snmp_errstring(requestPdu->errindex));
fprintf(stderr, "session->s_errno %d,session->s_snmp_errno %d \n", session->s_errno, session->s_snmp_errno);
}
if(responsePdu)
{
snmp_free_pdu(responsePdu);
}
snmp_close(session);
}
}
else
return false;
return true;
}
I'm just solving the problem. When I checked the internet I realize missing init_snmp("snmpapp"); function in my code. After adding init snmp, v3 set get message is send perfectly.
snmp_session *snmptypes::fCreateSession(QString IP)
{
struct snmp_session session;
init_snmp("snmpapp");
snmp_sess_init(&session);
session.peername = strdup(IP.toAscii());
.....
}
Maybe it would be a useful answer for people who will have the same problem.
i have difficulties in using LZMA SDK in my application.
I would like to create a kind of single file compression tool. I dont need any directory support, just need only the LZMA2 stream. But i have no idea on how LZMA SDK is to be used for this.
Please can anyone give me a little example on how the LZMA SDK can be used under C++?
I think that it's a properly little example to use LZMA SDK.
/* LzmaUtil.c -- Test application for LZMA compression
2008-08-05
Igor Pavlov
public domain */
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../LzmaDec.h"
#include "../LzmaEnc.h"
#include "../Alloc.h"
const char *kCantReadMessage = "Can not read input file";
const char *kCantWriteMessage = "Can not write output file";
const char *kCantAllocateMessage = "Can not allocate memory";
const char *kDataErrorMessage = "Data error";
static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
static void SzFree(void *p, void *address) { p = p; MyFree(address); }
static ISzAlloc g_Alloc = { SzAlloc, SzFree };
#define kInBufferSize (1 << 15)
#define kOutBufferSize (1 << 15)
unsigned char g_InBuffer[kInBufferSize];
unsigned char g_OutBuffer[kOutBufferSize];
size_t MyReadFile(FILE *file, void *data, size_t size)
{ return fread(data, 1, size, file); }
int MyReadFileAndCheck(FILE *file, void *data, size_t size)
{ return (MyReadFile(file, data, size) == size); }
size_t MyWriteFile(FILE *file, const void *data, size_t size)
{
if (size == 0)
return 0;
return fwrite(data, 1, size, file);
}
int MyWriteFileAndCheck(FILE *file, const void *data, size_t size)
{ return (MyWriteFile(file, data, size) == size); }
long MyGetFileLength(FILE *file)
{
long length;
fseek(file, 0, SEEK_END);
length = ftell(file);
fseek(file, 0, SEEK_SET);
return length;
}
void PrintHelp(char *buffer)
{
strcat(buffer, "\nLZMA Utility 4.58 Copyright (c) 1999-2008 Igor Pavlov 2008-04-11\n"
"\nUsage: lzma <e|d> inputFile outputFile\n"
" e: encode file\n"
" d: decode file\n");
}
int PrintError(char *buffer, const char *message)
{
strcat(buffer, "\nError: ");
strcat(buffer, message);
strcat(buffer, "\n");
return 1;
}
int PrintErrorNumber(char *buffer, SRes val)
{
sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
return 1;
}
int PrintUserError(char *buffer)
{
return PrintError(buffer, "Incorrect command");
}
#define IN_BUF_SIZE (1 << 16)
#define OUT_BUF_SIZE (1 << 16)
static int Decode(FILE *inFile, FILE *outFile, char *rs)
{
UInt64 unpackSize;
int thereIsSize; /* = 1, if there is uncompressed size in headers */
int i;
int res = 0;
CLzmaDec state;
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
unsigned char header[LZMA_PROPS_SIZE + 8];
/* Read and parse header */
if (!MyReadFileAndCheck(inFile, header, sizeof(header)))
return PrintError(rs, kCantReadMessage);
unpackSize = 0;
thereIsSize = 0;
for (i = 0; i < 8; i++)
{
unsigned char b = header[LZMA_PROPS_SIZE + i];
if (b != 0xFF)
thereIsSize = 1;
unpackSize += (UInt64)b << (i * 8);
}
LzmaDec_Construct(&state);
res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
if (res != SZ_OK)
return res;
{
Byte inBuf[IN_BUF_SIZE];
Byte outBuf[OUT_BUF_SIZE];
size_t inPos = 0, inSize = 0, outPos = 0;
LzmaDec_Init(&state);
for (;;)
{
if (inPos == inSize)
{
inSize = MyReadFile(inFile, inBuf, IN_BUF_SIZE);
inPos = 0;
}
{
SizeT inProcessed = inSize - inPos;
SizeT outProcessed = OUT_BUF_SIZE - outPos;
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
ELzmaStatus status;
if (thereIsSize && outProcessed > unpackSize)
{
outProcessed = (SizeT)unpackSize;
finishMode = LZMA_FINISH_END;
}
res = LzmaDec_DecodeToBuf(&state, outBuf + outPos, &outProcessed,
inBuf + inPos, &inProcessed, finishMode, &status);
inPos += (UInt32)inProcessed;
outPos += outProcessed;
unpackSize -= outProcessed;
if (outFile != 0)
MyWriteFile(outFile, outBuf, outPos);
outPos = 0;
if (res != SZ_OK || thereIsSize && unpackSize == 0)
break;
if (inProcessed == 0 && outProcessed == 0)
{
if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
res = SZ_ERROR_DATA;
break;
}
}
}
}
LzmaDec_Free(&state, &g_Alloc);
return res;
}
typedef struct _CFileSeqInStream
{
ISeqInStream funcTable;
FILE *file;
} CFileSeqInStream;
static SRes MyRead(void *p, void *buf, size_t *size)
{
if (*size == 0)
return SZ_OK;
*size = MyReadFile(((CFileSeqInStream*)p)->file, buf, *size);
/*
if (*size == 0)
return SZE_FAIL;
*/
return SZ_OK;
}
typedef struct _CFileSeqOutStream
{
ISeqOutStream funcTable;
FILE *file;
} CFileSeqOutStream;
static size_t MyWrite(void *pp, const void *buf, size_t size)
{
return MyWriteFile(((CFileSeqOutStream *)pp)->file, buf, size);
}
static SRes Encode(FILE *inFile, FILE *outFile, char *rs)
{
CLzmaEncHandle enc;
SRes res;
CFileSeqInStream inStream;
CFileSeqOutStream outStream;
CLzmaEncProps props;
enc = LzmaEnc_Create(&g_Alloc);
if (enc == 0)
return SZ_ERROR_MEM;
inStream.funcTable.Read = MyRead;
inStream.file = inFile;
outStream.funcTable.Write = MyWrite;
outStream.file = outFile;
LzmaEncProps_Init(&props);
res = LzmaEnc_SetProps(enc, &props);
if (res == SZ_OK)
{
Byte header[LZMA_PROPS_SIZE + 8];
size_t headerSize = LZMA_PROPS_SIZE;
UInt64 fileSize;
int i;
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
fileSize = MyGetFileLength(inFile);
for (i = 0; i < 8; i++)
header[headerSize++] = (Byte)(fileSize >> (8 * i));
if (!MyWriteFileAndCheck(outFile, header, headerSize))
return PrintError(rs, "writing error");
if (res == SZ_OK)
res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
NULL, &g_Alloc, &g_Alloc);
}
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
return res;
}
int main2(int numArgs, const char *args[], char *rs)
{
FILE *inFile = 0;
FILE *outFile = 0;
char c;
int res;
int encodeMode;
if (numArgs == 1)
{
PrintHelp(rs);
return 0;
}
if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
return PrintUserError(rs);
c = args[1][0];
encodeMode = (c == 'e' || c == 'E');
if (!encodeMode && c != 'd' && c != 'D')
return PrintUserError(rs);
{
size_t t4 = sizeof(UInt32);
size_t t8 = sizeof(UInt64);
if (t4 != 4 || t8 != 8)
return PrintError(rs, "LZMA UTil needs correct UInt32 and UInt64");
}
inFile = fopen(args[2], "rb");
if (inFile == 0)
return PrintError(rs, "Can not open input file");
if (numArgs > 3)
{
outFile = fopen(args[3], "wb+");
if (outFile == 0)
return PrintError(rs, "Can not open output file");
}
else if (encodeMode)
PrintUserError(rs);
if (encodeMode)
{
res = Encode(inFile, outFile, rs);
}
else
{
res = Decode(inFile, outFile, rs);
}
if (outFile != 0)
fclose(outFile);
fclose(inFile);
if (res != SZ_OK)
{
if (res == SZ_ERROR_MEM)
return PrintError(rs, kCantAllocateMessage);
else if (res == SZ_ERROR_DATA)
return PrintError(rs, kDataErrorMessage);
else
return PrintErrorNumber(rs, res);
}
return 0;
}
int MY_CDECL main(int numArgs, const char *args[])
{
char rs[800] = { 0 };
int res = main2(numArgs, args, rs);
printf(rs);
return res;
}
Also you can see it at:
http://read.pudn.com/downloads151/sourcecode/zip/656407/7z460/C/LzmaUtil/LzmaUtil.c__.htm
http://read.pudn.com/downloads157/sourcecode/zip/698262/LZMA/LzmaUtil.c__.htm
I recently found a nice example, written in C++. Credit goes to GH user Treeki who published the original gist:
// note: -D_7ZIP_ST is required when compiling on non-Windows platforms
// g++ -o lzma_sample -std=c++14 -D_7ZIP_ST lzma_sample.cpp LzmaDec.c LzmaEnc.c LzFind.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <memory>
#include "LzmaEnc.h"
#include "LzmaDec.h"
static void *_lzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void _lzmaFree(ISzAllocPtr, void *addr) {
if (!addr)
return;
delete[] reinterpret_cast<uint8_t *>(addr);
}
static ISzAlloc _allocFuncs = {
_lzmaAlloc, _lzmaFree
};
std::unique_ptr<uint8_t[]> lzmaCompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
std::unique_ptr<uint8_t[]> result;
// set up properties
CLzmaEncProps props;
LzmaEncProps_Init(&props);
if (inputSize >= (1 << 20))
props.dictSize = 1 << 20; // 1mb dictionary
else
props.dictSize = inputSize; // smaller dictionary = faster!
props.fb = 40;
// prepare space for the encoded properties
SizeT propsSize = 5;
uint8_t propsEncoded[5];
// allocate some space for the compression output
// this is way more than necessary in most cases...
// but better safe than sorry
// (a smarter implementation would use a growing buffer,
// but this requires a bunch of fuckery that is out of
/// scope for this simple example)
SizeT outputSize64 = inputSize * 1.5;
if (outputSize64 < 1024)
outputSize64 = 1024;
auto output = std::make_unique<uint8_t[]>(outputSize64);
int lzmaStatus = LzmaEncode(
output.get(), &outputSize64, input, inputSize,
&props, propsEncoded, &propsSize, 0,
NULL,
&_allocFuncs, &_allocFuncs);
*outputSize = outputSize64 + 13;
if (lzmaStatus == SZ_OK) {
// tricky: we have to generate the LZMA header
// 5 bytes properties + 8 byte uncompressed size
result = std::make_unique<uint8_t[]>(outputSize64 + 13);
uint8_t *resultData = result.get();
memcpy(resultData, propsEncoded, 5);
for (int i = 0; i < 8; i++)
resultData[5 + i] = (inputSize >> (i * 8)) & 0xFF;
memcpy(resultData + 13, output.get(), outputSize64);
}
return result;
}
std::unique_ptr<uint8_t[]> lzmaDecompress(const uint8_t *input, uint32_t inputSize, uint32_t *outputSize) {
if (inputSize < 13)
return NULL; // invalid header!
// extract the size from the header
UInt64 size = 0;
for (int i = 0; i < 8; i++)
size |= (input[5 + i] << (i * 8));
if (size <= (256 * 1024 * 1024)) {
auto blob = std::make_unique<uint8_t[]>(size);
ELzmaStatus lzmaStatus;
SizeT procOutSize = size, procInSize = inputSize - 13;
int status = LzmaDecode(blob.get(), &procOutSize, &input[13], &procInSize, input, 5, LZMA_FINISH_END, &lzmaStatus, &_allocFuncs);
if (status == SZ_OK && procOutSize == size) {
*outputSize = size;
return blob;
}
}
return NULL;
}
void hexdump(const uint8_t *buf, int size) {
int lines = (size + 15) / 16;
for (int i = 0; i < lines; i++) {
printf("%08x | ", i * 16);
int lineMin = i * 16;
int lineMax = lineMin + 16;
int lineCappedMax = (lineMax > size) ? size : lineMax;
for (int j = lineMin; j < lineCappedMax; j++)
printf("%02x ", buf[j]);
for (int j = lineCappedMax; j < lineMax; j++)
printf(" ");
printf("| ");
for (int j = lineMin; j < lineCappedMax; j++) {
if (buf[j] >= 32 && buf[j] <= 127)
printf("%c", buf[j]);
else
printf(".");
}
printf("\n");
}
}
void testIt(const uint8_t *input, int size) {
printf("Test Input:\n");
hexdump(input, size);
uint32_t compressedSize;
auto compressedBlob = lzmaCompress(input, size, &compressedSize);
if (compressedBlob) {
printf("Compressed:\n");
hexdump(compressedBlob.get(), compressedSize);
} else {
printf("Nope, we screwed it\n");
return;
}
// let's try decompressing it now
uint32_t decompressedSize;
auto decompressedBlob = lzmaDecompress(compressedBlob.get(), compressedSize, &decompressedSize);
if (decompressedBlob) {
printf("Decompressed:\n");
hexdump(decompressedBlob.get(), decompressedSize);
} else {
printf("Nope, we screwed it (part 2)\n");
return;
}
printf("----------\n");
}
void testIt(const char *string) {
testIt((const uint8_t *)string, strlen(string));
}
int main(int argc, char **argv) {
testIt("a");
testIt("here is a cool string");
testIt("here's something that should compress pretty well: abcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdefabcdef");
return 0;
}
You can refer to this file on how to use lzma2。
https://github.com/Tencent/libpag/blob/aab6391e455193c8ec5b8e2031b495b3fe77b034/test/framework/utils/LzmaUtil.cpp
/////////////////////////////////////////////////////////////////////////////////////////////////
//
// Tencent is pleased to support the open source community by making libpag available.
//
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
// except in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// unless required by applicable law or agreed to in writing, software distributed under the
// license is distributed on an "as is" basis, without warranties or conditions of any kind,
// either express or implied. see the license for the specific language governing permissions
// and limitations under the license.
//
/////////////////////////////////////////////////////////////////////////////////////////////////
#include "LzmaUtil.h"
#include "test/framework/lzma/Lzma2DecMt.h"
#include "test/framework/lzma/Lzma2Enc.h"
namespace pag {
static void* LzmaAlloc(ISzAllocPtr, size_t size) {
return new uint8_t[size];
}
static void LzmaFree(ISzAllocPtr, void* address) {
if (!address) {
return;
}
delete[] reinterpret_cast<uint8_t*>(address);
}
static ISzAlloc gAllocFuncs = {LzmaAlloc, LzmaFree};
class SequentialOutStream {
public:
virtual ~SequentialOutStream() = default;
virtual bool write(const void* data, size_t size) = 0;
};
class SequentialInStream {
public:
virtual ~SequentialInStream() = default;
virtual bool read(void* data, size_t size, size_t* processedSize) = 0;
};
struct CSeqInStreamWrap {
ISeqInStream vt;
std::unique_ptr<SequentialInStream> inStream;
};
struct CSeqOutStreamWrap {
ISeqOutStream vt;
std::unique_ptr<SequentialOutStream> outStream;
};
class BuffPtrInStream : public SequentialInStream {
public:
explicit BuffPtrInStream(const uint8_t* buffer, size_t bufferSize)
: buffer(buffer), bufferSize(bufferSize) {
}
bool read(void* data, size_t size, size_t* processedSize) override {
if (processedSize) {
*processedSize = 0;
}
if (size == 0 || position >= bufferSize) {
return true;
}
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
memcpy(data, static_cast<const uint8_t*>(buffer) + position, remain);
position += remain;
if (processedSize) {
*processedSize = remain;
}
return true;
}
private:
const uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
class VectorOutStream : public SequentialOutStream {
public:
explicit VectorOutStream(std::vector<uint8_t>* buffer) : buffer(buffer) {
}
bool write(const void* data, size_t size) override {
auto oldSize = buffer->size();
buffer->resize(oldSize + size);
memcpy(&(*buffer)[oldSize], data, size);
return true;
}
private:
std::vector<uint8_t>* buffer;
};
class BuffPtrSeqOutStream : public SequentialOutStream {
public:
BuffPtrSeqOutStream(uint8_t* buffer, size_t size) : buffer(buffer), bufferSize(size) {
}
bool write(const void* data, size_t size) override {
auto remain = bufferSize - position;
if (remain > size) {
remain = size;
}
if (remain != 0) {
memcpy(buffer + position, data, remain);
position += remain;
}
return remain != 0 || size == 0;
}
private:
uint8_t* buffer = nullptr;
size_t bufferSize = 0;
size_t position = 0;
};
static const size_t kStreamStepSize = 1 << 31;
static SRes MyRead(const ISeqInStream* p, void* data, size_t* size) {
CSeqInStreamWrap* wrap = CONTAINER_FROM_VTBL(p, CSeqInStreamWrap, vt);
auto curSize = (*size < kStreamStepSize) ? *size : kStreamStepSize;
if (!wrap->inStream->read(data, curSize, &curSize)) {
return SZ_ERROR_READ;
}
*size = curSize;
return SZ_OK;
}
static size_t MyWrite(const ISeqOutStream* p, const void* buf, size_t size) {
auto* wrap = CONTAINER_FROM_VTBL(p, CSeqOutStreamWrap, vt);
if (wrap->outStream->write(buf, size)) {
return size;
}
return 0;
}
class Lzma2Encoder {
public:
Lzma2Encoder() {
encoder = Lzma2Enc_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Encoder() {
Lzma2Enc_Destroy(encoder);
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (encoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto inputSize = inputData->size();
CLzma2EncProps lzma2Props;
Lzma2EncProps_Init(&lzma2Props);
lzma2Props.lzmaProps.dictSize = inputSize;
lzma2Props.lzmaProps.level = 9;
lzma2Props.numTotalThreads = 4;
Lzma2Enc_SetProps(encoder, &lzma2Props);
std::vector<uint8_t> outBuf;
outBuf.resize(1 + 8);
outBuf[0] = Lzma2Enc_WriteProperties(encoder);
for (int i = 0; i < 8; i++) {
outBuf[1 + i] = static_cast<uint8_t>(inputSize >> (8 * i));
}
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(
static_cast<const uint8_t*>(inputData->data()), inputSize);
CSeqOutStreamWrap outStream = {};
outStream.vt.Write = MyWrite;
outStream.outStream = std::make_unique<VectorOutStream>(&outBuf);
auto status =
Lzma2Enc_Encode2(encoder, &outStream.vt, nullptr, nullptr, &inWrap.vt, nullptr, 0, nullptr);
if (status != SZ_OK) {
return nullptr;
}
return Data::MakeWithCopy(&outBuf[0], outBuf.size());
}
private:
CLzma2EncHandle encoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Compress(const std::shared_ptr<Data>& pixelData) {
Lzma2Encoder encoder;
return encoder.code(pixelData);
}
class Lzma2Decoder {
public:
Lzma2Decoder() {
decoder = Lzma2DecMt_Create(&gAllocFuncs, &gAllocFuncs);
}
~Lzma2Decoder() {
if (decoder) {
Lzma2DecMt_Destroy(decoder);
}
}
std::shared_ptr<Data> code(const std::shared_ptr<Data>& inputData) {
if (decoder == nullptr || inputData == nullptr || inputData->size() == 0) {
return nullptr;
}
auto input = static_cast<const uint8_t*>(inputData->data());
auto inputSize = inputData->size() - 9;
Byte prop = static_cast<const Byte*>(input)[0];
CLzma2DecMtProps props;
Lzma2DecMtProps_Init(&props);
props.inBufSize_ST = inputSize;
props.numThreads = 1;
UInt64 outBufferSize = 0;
for (int i = 0; i < 8; i++) {
outBufferSize |= (input[1 + i] << (i * 8));
}
auto outBuffer = new uint8_t[outBufferSize];
CSeqInStreamWrap inWrap = {};
inWrap.vt.Read = MyRead;
inWrap.inStream = std::make_unique<BuffPtrInStream>(input + 9, inputSize);
CSeqOutStreamWrap outWrap = {};
outWrap.vt.Write = MyWrite;
outWrap.outStream = std::make_unique<BuffPtrSeqOutStream>(outBuffer, outBufferSize);
UInt64 inProcessed = 0;
int isMT = false;
auto res = Lzma2DecMt_Decode(decoder, prop, &props, &outWrap.vt, &outBufferSize, 1, &inWrap.vt,
&inProcessed, &isMT, nullptr);
if (res == SZ_OK && inputSize == inProcessed) {
return Data::MakeAdopted(outBuffer, outBufferSize, Data::DeleteProc);
}
delete[] outBuffer;
return nullptr;
}
private:
CLzma2DecMtHandle decoder = nullptr;
};
std::shared_ptr<Data> LzmaUtil::Decompress(const std::shared_ptr<Data>& data) {
Lzma2Decoder decoder;
return decoder.code(data);
}
} // namespace pag
I writing program for the Windows registry and trying to query values from it, but even if I running my own program with the permissions of Administrator, I can not read all parameters and got error code 5 - Access Denied for some values. But at the same time standard regedit could show me that value. What did i doing wrong?
I have a class for the registry RegistryClass
RegistryClass.h:
class RegistryClass
{
HKEY hKey;
public:
int GetCountOfKeys();
bool OpenKey(HKEY key, std::string path);
void EnumKeys(char ** result, int * count);
...
}
RegistryClass.cpp
#include "RegistryClass.h"
...
bool RegistryClass::OpenKey(HKEY key, std::string path)
{
if(RegOpenKeyExA(key,path.c_str(),NULL,KEY_ALL_ACCESS,&hKey) == ERROR_SUCCESS)
{
return true;
}
hKey = NULL;
return false;
}
int RegistryClass::GetCountOfKeys()
{
DWORD count = 0;
char keyName [256];
DWORD len = 255;
while(1)
{
if(RegEnumKeyExA(hKey,count,keyName,&len,NULL,NULL,NULL,NULL) != ERROR_SUCCESS)
break;
count++;
len = 255;
}
return count;
}
void RegistryClass::EnumKeys(char ** result, int * count)
{
if(hKey == NULL)
return;
*count = 0;
DWORD dwIndex = 0; // current key
char keyName [255]; // current key name
DWORD lpcchName = 255; // name length
int error;
do
{
error = RegEnumKeyExA(hKey,dwIndex,keyName,&lpcchName,NULL,NULL,NULL,NULL);
if(error == ERROR_SUCCESS)
{
memcpy(result[(*count)],keyName,lpcchName);
(*count)++;
}
dwIndex++;
lpcchName = 255;
}while(error == ERROR_SUCCESS);
}
in main program i trying to retrive keys
void MainWindow::InitializeFirstState()
{
item_HKEY_CLASSES_ROOT = new QTreeWidgetItem();
item_HKEY_CLASSES_ROOT->setText(0,"HKEY_CLASSES_ROOT");
// and other keys
...
tree->addTopLevelItem(item_HKEY_CLASSES_ROOT);
...
AddInternalKeys(item_HKEY_CLASSES_ROOT,true);
...
}
...
void AddInternalKeys(QTreeWidgetItem * item, bool rec)
{
std::string currentPath = GetFullPathKey(item);
// first key name
std::string keyName = GetParentKeyName(item);
RegistryClass * regC = new RegistryClass();
HKEY key;
if(strcmp(keyName.c_str(),"HKEY_CLASSES_ROOT") == 0)
{
key = HKEY_CLASSES_ROOT;
}
else if(strcmp(keyName.c_str(),"HKEY_CURRENT_USER") == 0)
{
key = HKEY_CURRENT_USER;
}
else if(strcmp(keyName.c_str(),"HKEY_LOCAL_MACHINE") == 0)
{
key = HKEY_LOCAL_MACHINE;
}
else if(strcmp(keyName.c_str(),"HKEY_USERS") == 0)
{
key = HKEY_USERS;
}
else // HKEY_CURRENT_CONFIG
{
key = HKEY_CURRENT_CONFIG;
}
if(regC->OpenKey(key,currentPath) == true)
{
internalLog->print("key opened succesfully\n");
}
else internalLog->print("key was not opened\n");
int count = regC->GetCountOfKeys();
char ** keys = (char **) malloc(sizeof(char *) * count);
for(int i=0;i<count;i++)
{
keys[i] = (char *) malloc(sizeof(char) * 256);
memset(keys[i],0,sizeof(char) * 256);
}
regC->EnumKeys(keys,&count);
regC->CloseKey();
delete regC;
QTreeWidgetItem * newItem;
count--;
while(count >= 0)
{
newItem = new QTreeWidgetItem();
newItem->setText(0,keys[count]);
item->addChild(newItem);
std::string str = keys[count];
AddKeyNames(newItem,str);
free(keys[count]);
if(rec == true)
AddInternalKeys(newItem,false);
count--;
}
free(keys);
}
You are asking for too much access. You are asking for KEY_ALL_ACCESS when all you actually need is KEY_READ. You do not have all-access permission, but you do have read permission.
I have a problem where only sometimes when I call avformat_close_input(&pFormatCtx) and it results in malloc check failed and my application crashes.
I really need to use ffmpeg because I need to grab a thumbnail of a video to show in a list and I cannot find an alternative library.
Can anybody see something in my code where I am doing something wrong when using this library which may cause this malloc check failed problem?
bool MuteCamera::PullFrame( )
{
pMJPEGCodec = avcodec_find_encoder(CODEC_ID_MJPEG );
bool bRet = false;
int videoStream = -1;
AVFrame *pFrame=NULL;
AVFrame *pFrameRGB=NULL;
AVPacket packet;
int frameFinished=0;
//AVDictionary *optionsDict = NULL;
AVInputFormat *pFormat = NULL;
const char formatName[] = "mp4";
if (!(pFormat = av_find_input_format(formatName))) {
printf("can't find input format %s\n", formatName);
return -1;
}
AVFormatContext *pFormatCtx = NULL;
pFormatCtx=avformat_alloc_context();
if(pFormatCtx == NULL)
{
printf("\n NULL CONTEXT \n ");
return -1;
}
if(avformat_open_input (&pFormatCtx, capturedUrl.data(), pFormat, NULL) == 0 )
{
for(int i=0; i<(int)pFormatCtx->nb_streams; i++)
{
if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if(videoStream >= 0 )
{
AVCodecContext *pCodecCtx = pFormatCtx->streams[videoStream]->codec;
AVCodec *pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec != NULL)
{
if( avcodec_open2(pCodecCtx, pCodec, NULL) >= 0 )
{
pFrame=avcodec_alloc_frame();
if(pFrame != NULL)
{
frameFinished = 0;
while(av_read_frame(pFormatCtx, &packet)>=0)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished)
{
printf("\n FRAMEFINISHED \n ");
QString *uu = new QString(capturedUrl.data());//
uu->replace(".mp4", "thumbnail.jpg");
WriteJPEG(pCodecCtx, pFrame, uu->toLatin1().data(), PIX_FMT_YUVJ420P);
if(viewingVideos && viewingFromDifferent)
{
QVariantMap map = QVariantMap();
map["title"] = actualFilename;
map["path"] = actualFilename.replace(".mp4", "thumbnail.jpg");// QString("asset:///white_photo.png");
m_listDataModel << map;
}
delete uu;
av_free_packet(&packet);
break;
}
else
{
printf("\n FRAMENOTFINISHED \n ");
}
}
av_free_packet(&packet);
}
av_free(pFrameRGB);
av_free(pFrame);
avcodec_close(pCodecCtx);
//av_free(pCodecCtx);
cout << "\n before free formatctx \n";
cout.flush();
if(pFormatCtx)
avformat_close_input(&pFormatCtx);
cout << "\n after free formatctx \n";
cout.flush();
}
else
bRet = false;
}
else
bRet = false;
}
else
bRet = false;
}
else
bRet = false;
}
return bRet;
}
bool WriteJPEG (AVCodecContext *pCodecCtx, AVFrame *pFrame, char cFileName[], PixelFormat pix)
{
int complete = 0;
bool bRet = false;
int out_buf_size;
uint8_t *out_buf;
AVCodecContext *pMJPEGCtx = avcodec_alloc_context3(pMJPEGCodec);
if( pMJPEGCtx )
{
pMJPEGCtx->bit_rate = pCodecCtx->bit_rate;
pMJPEGCtx->width = pCodecCtx->width;
pMJPEGCtx->height = pCodecCtx->height;
pMJPEGCtx->pix_fmt = pix;
pMJPEGCtx->codec_id = CODEC_ID_MJPEG;
pMJPEGCtx->codec_type = AVMEDIA_TYPE_VIDEO;
pMJPEGCtx->time_base.num = pCodecCtx->time_base.num;
pMJPEGCtx->time_base.den = pCodecCtx->time_base.den;
pMJPEGCtx->time_base= (AVRational){1,29.7};
if( pMJPEGCodec && (avcodec_open2( pMJPEGCtx, pMJPEGCodec, NULL) >= 0) )
{
AVFrame *oframe;
oframe = avcodec_alloc_frame();
if(oframe == NULL)
{
printf("\n (oframe == NULL");
fflush(stdout);
}
/* calculate the bytes needed for the output image and create buffer for the output image */
out_buf_size = avpicture_get_size(pMJPEGCtx->pix_fmt,
pMJPEGCtx->width,
pMJPEGCtx->height);
out_buf = (uint8_t *)av_malloc(out_buf_size * sizeof(uint8_t));
if (out_buf == NULL) {
fprintf(stderr, "cannot allocate output data buffer!\n");
//ret = -ENOMEM;
}
avpicture_alloc((AVPicture *)oframe, pMJPEGCtx->pix_fmt, pMJPEGCtx->width, pMJPEGCtx->height);
struct SwsContext *sws;
sws = sws_getContext(pMJPEGCtx->width, pMJPEGCtx->height, pCodecCtx->pix_fmt,
pMJPEGCtx->width, pMJPEGCtx->height, pMJPEGCtx->pix_fmt, SWS_BILINEAR,
NULL, NULL, NULL);
sws_scale(sws, (const uint8_t **)pFrame->data, pFrame->linesize,
0, pMJPEGCtx->height, &oframe->data[0], &oframe->linesize[0]);
sws_freeContext(sws);
AVPacket pp2;
av_init_packet(&pp2);
pp2.data = NULL;
pp2.size = 0;
avcodec_encode_video2(pMJPEGCtx, &pp2, oframe, &complete);
if(complete)
{
printf("\n packet recieved");
fflush(stdout);
}
else
{
printf("\n packet NOT recieved");
fflush(stdout);
}
if( SaveFrameJpeg(pp2.size, pp2.data, cFileName ) )
bRet = true;
av_free(oframe);
avcodec_close(pMJPEGCtx);
av_free_packet(&pp2);
av_free(out_buf);
av_free(pMJPEGCtx);
}
else
{
printf("\n problem!!");
fflush(stdout);
}
return bRet;
}
}
bool SaveFrameJpeg(int nszBuffer, uint8_t *buffer, char cOutFileName[])
{
bool bRet = false;
FILE *pFile;
if( nszBuffer > 0 )
{
if(0 == 0 )
{
printf("\n start SaveFrameJpeg=%d",nszBuffer );
fflush(stdout);
pFile= fopen(cOutFileName, "wb");
fwrite(buffer, sizeof(uint8_t), nszBuffer, pFile);
bRet = true;
fclose(pFile);
printf("\n end SaveFrameJpeg=%d",nszBuffer );
fflush(stdout);
}
}
return bRet;
}
bool newPullFrame(const std::string& capturedUrl)
{
AVCodec* pMJPEGCodec = avcodec_find_encoder(CODEC_ID_MJPEG );
int videoStream = -1;
AVDictionary *optionsDict = NULL;
AVInputFormat *pFormat = NULL;
const char formatName[] = "mp4";
if (!(pFormat = av_find_input_format(formatName)))
{
std::cout << "can't find input format " << formatName << "\n";
return false;
}
AVFormatContextHandle FormatCtx(avformat_alloc_context());
if(!FormatCtx.is_valid())
{
std::cout << "\n NULL CONTEXT \n ";
return false;
}
if(avformat_open_input (&FormatCtx, capturedUrl.c_str(), pFormat, NULL))
return false;
for(int i=0; i<(int)FormatCtx->nb_streams; i++)
{
if(FormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if(videoStream < 0 )
return false;
CodecContextHandle CodecCtx(FormatCtx->streams[videoStream]->codec, avcodec_close);
AVCodec *pCodec = avcodec_find_decoder(CodecCtx->codec_id);
if(pCodec == NULL)
return false;
if( avcodec_open2(CodecCtx, pCodec, &optionsDict) < 0 )
return false;
FrameHandle Frame(avcodec_alloc_frame(), av_free);
if(!Frame.is_valid())
return false;
int frameFinished=0;
AVPacket packet;
while(av_read_frame(FormatCtx, &packet)>=0)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video2(CodecCtx, Frame, &frameFinished, &packet);
if(frameFinished)
{
std::string uu (capturedUrl);
size_t pos = capturedUrl.rfind(".mp4");
uu.replace(pos, 4, "thumbnail.jpg");
// save the frame to file
int Bytes = avpicture_get_size(PIX_FMT_YUVJ420P, CodecCtx->width, CodecCtx->height);
BufferHandle buffer((uint8_t*)av_malloc(Bytes*sizeof(uint8_t)), av_free);
CodecContextHandle OutContext(avcodec_alloc_context3(NULL), free_context);
OutContext->bit_rate = CodecCtx->bit_rate;
OutContext->width = CodecCtx->width;
OutContext->height = CodecCtx->height;
OutContext->pix_fmt = PIX_FMT_YUVJ420P;
OutContext->codec_id = CODEC_ID_MJPEG;
OutContext->codec_type = AVMEDIA_TYPE_VIDEO;
OutContext->time_base.num = CodecCtx->time_base.num;
OutContext->time_base.den = CodecCtx->time_base.den;
OutContext->time_base= (AVRational){1,29.7};
AVCodec *OutCodec = avcodec_find_encoder(OutContext->codec_id);
avcodec_open2(OutContext, OutCodec, NULL);
OutContext->mb_lmin = OutContext->lmin = OutContext->qmin * 118;
OutContext->mb_lmax = OutContext->lmax = OutContext->qmax * 118;
OutContext->flags = 2;
OutContext->global_quality = OutContext->qmin * 118;
Frame->pts = 1;
Frame->quality = OutContext->global_quality;
int ActualSize = avcodec_encode_video(OutContext, buffer, Bytes, Frame);
std::ofstream file(uu.data(), std::ios_base::binary | std::ios_base::out);
file.write((const char*)(uint8_t*)buffer, ActualSize);
file.close();
av_free_packet(&packet);
av_free(Frame);
break;
}
else
{
std::cout << " new pullframe frameNOTfinished\n";
cout.flush();
}
//if(CodecCtx->refcounted_frames == 1)
av_free(Frame);
}
av_free_packet(&packet);
}
return true;
}
It looks to me like you need to move your call to av_free_packet(&packet) inside your while loop. So you currently have:
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// A bunch of operations here
}
// this is not the right place for this
av_free_packet(&packet);
Instead you should have
while(av_read_frame(pFormatCtx, &packet)>=0)
{
// A bunch of operations here
// this needs to be called for every call to av_read_frame()
// so it must be inside the while loop
av_free_packet(&packet);
}
See here for further details.
Considering that you writing this in C++ you could consider creating some simple RAII wrappers around these resources to make your resource management much easier.
EDIT
Based on your feedback it seems that this change that I recommended didn't do it. So I revisited the code. I implemented my own save to Jpeg as I could not see yours - though for test purposes it simply keeps over-writing the same file.
In order to simplify the code and get a handle on the resource management I implemented some "smart pointers" for the ffmpeg resources. These automatically clean up at scope exit. I cannot see a resource leak when running through this code and it correctly generates each frame as a jpeg file.
See if you get any value out of this:
extern "C" {
#include <libavdevice\avdevice.h>
#include <libavformat\avformat.h>
#include <libavfilter\avfilter.h>
#include <libavcodec\avcodec.h>
#include <libswscale\swscale.h>
}
#include <iostream>
#include <fstream>
#include <ios>
#include <type_traits>
template<typename T, typename D>
class AVHandle
{
T *val;
typedef D* deleter_t;
deleter_t deleter;
// not default constructible
AVHandle();
// non copiable
AVHandle(const AVHandle&);
AVHandle& operator=(const AVHandle&);
public:
AVHandle(T *in, deleter_t del) : val(in), deleter(del)
{}
operator T *()
{
return val;
}
T* operator->()
{
return val;
}
bool is_valid()
{
return val != 0;
}
~AVHandle()
{
deleter(val);
}
};
typedef AVHandle<AVFrame, void (void*)> FrameHandle;
typedef AVHandle<AVCodecContext, int (AVCodecContext*)> CodecContextHandle;
typedef AVHandle<uint8_t, void(void*)> BufferHandle;
class AVFormatContextHandle
{
AVFormatContext *val;
// not default constrcutible
AVFormatContextHandle();
// non copiable
AVFormatContextHandle(const AVFormatContextHandle&);
AVFormatContextHandle& operator=(const AVFormatContextHandle&);
public:
AVFormatContextHandle(AVFormatContext *ctx) : val(ctx)
{}
operator AVFormatContext *()
{
return val;
}
AVFormatContext* operator ->()
{
return val;
}
AVFormatContext** operator&()
{
return &val;
}
bool is_valid()
{
return val != 0;
}
~AVFormatContextHandle()
{
if(val)
avformat_close_input(&val);
}
};
int free_context(AVCodecContext* c)
{
int ret = avcodec_close(c);
av_free(c);
return ret;
}
bool PullFrame(const std::string& capturedUrl)
{
AVCodec* pMJPEGCodec = avcodec_find_encoder(CODEC_ID_MJPEG );
int videoStream = -1;
AVDictionary *optionsDict = NULL;
AVInputFormat *pFormat = NULL;
const char formatName[] = "mp4";
if (!(pFormat = av_find_input_format(formatName)))
{
std::cout << "can't find input format " << formatName << "\n";
return false;
}
AVFormatContextHandle FormatCtx(avformat_alloc_context());
if(!FormatCtx.is_valid())
{
std::cout << "\n NULL CONTEXT \n ";
return false;
}
if(avformat_open_input (&FormatCtx, capturedUrl.c_str(), pFormat, NULL))
return false;
for(int i=0; i<(int)FormatCtx->nb_streams; i++)
{
if(FormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
{
videoStream=i;
break;
}
}
if(videoStream < 0 )
return false;
CodecContextHandle CodecCtx(FormatCtx->streams[videoStream]->codec, avcodec_close);
AVCodec *pCodec = avcodec_find_decoder(CodecCtx->codec_id);
if(pCodec == NULL)
return false;
if( avcodec_open2(CodecCtx, pCodec, &optionsDict) < 0 )
return false;
FrameHandle Frame(avcodec_alloc_frame(), av_free);
if(!Frame.is_valid())
return false;
int frameFinished=0;
AVPacket packet;
while(av_read_frame(FormatCtx, &packet)>=0)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video2(CodecCtx, Frame, &frameFinished, &packet);
if(frameFinished)
{
std::string uu (capturedUrl);
size_t pos = capturedUrl.rfind(".mp4");
uu.replace(pos, 4, "thumbnail.jpg");
// save the frame to file
int Bytes = avpicture_get_size(PIX_FMT_YUVJ420P, CodecCtx->width, CodecCtx->height);
BufferHandle buffer((uint8_t*)av_malloc(Bytes*sizeof(uint8_t)), av_free);
CodecContextHandle OutContext(avcodec_alloc_context3(NULL), free_context);
OutContext->bit_rate = CodecCtx->bit_rate;
OutContext->width = CodecCtx->width;
OutContext->height = CodecCtx->height;
OutContext->pix_fmt = PIX_FMT_YUVJ420P;
OutContext->codec_id = CODEC_ID_MJPEG;
OutContext->codec_type = AVMEDIA_TYPE_VIDEO;
OutContext->time_base.num = CodecCtx->time_base.num;
OutContext->time_base.den = CodecCtx->time_base.den;
AVCodec *OutCodec = avcodec_find_encoder(OutContext->codec_id);
avcodec_open2(OutContext, OutCodec, NULL);
OutContext->mb_lmin = OutContext->lmin = OutContext->qmin * 118;
OutContext->mb_lmax = OutContext->lmax = OutContext->qmax * 118;
OutContext->flags = 2;
OutContext->global_quality = OutContext->qmin * 118;
Frame->pts = 1;
Frame->quality = OutContext->global_quality;
int ActualSize = avcodec_encode_video(OutContext, buffer, Bytes, Frame);
std::ofstream file("c:\\temp\\output.jpg", std::ios_base::binary | std::ios_base::out);
file.write((const char*)(uint8_t*)buffer, ActualSize);
}
if(CodecCtx->refcounted_frames == 1)
av_frame_unref(Frame);
}
av_free_packet(&packet);
}
return true;
}
int main()
{
av_register_all();
while(true)
PullFrame("c:\\temp\\sample_mpeg4.mp4");
return 0;
}