2、lib7z-Memory从内存或网络解压数据(分析源码,修改源码)
来源:互联网 发布:淘宝商城客服 编辑:程序博客网 时间:2024/05/22 05:10
希望你有好运气能编译上一节我提供的Dec7z的源码,如果你成功了,接下来,我就分享一下分析7z源码并修改到符合目的的过程。
首先进入
BOOL Extra7zFileToPath(WCHAR* sTargetPath, HWND hwnd, BOOL bUpdate, char* pAllData, DWORD iLength)
这个函数,
CFileInStream archiveStream;//包含HANDLE句柄,Read和Seek CLookToRead lookStream; CSzArEx db;//压缩包内的文件名称和大小? SRes res; ISzAlloc allocImp;//包括malloc和free函数 ISzAlloc allocTempImp;//Win32 HeapAlloc和HeapFree这里主要的代码我都做了注释,关键点一是这个:
//(*函数指针Read,Seek,Skip等赋值 FileInStream_CreateVTable(&archiveStream);//这个好办 //这个尚未清楚 //也是用的上面的Read和Seek,但多了p->pos的操作 LookToRead_CreateVTable(&lookStream, False); //*)
通过分析7z解压的源码,就知道7z解压的最后手段无非就是fopen,fwrite在Windows系统下用宏判断定义了,读取和Seek函数,
无非就是CreateFile(打开文件),ReadFile(读物数据到内存 ),SetFilePointer(设置文件指针),CloseHandle(关闭打开的文件句柄)。
7z用了结构体的面向技术,最关键的两个是
typedef struct{ ISeekInStream s; CSzFile file;} CFileInStream;
typedef struct{ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);} ISeekInStream;最关键的读取和移动文件指针函数是
WRes File_Read(CSzFile *p, void *data, size_t *size);/* writes *size bytes */WRes File_Write(CSzFile *p, const void *data, size_t *size);WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);WRes File_GetLength(CSzFile *p, UInt64 *length);
其中ISeekInStream的Read函数指针通过分析正指向File_Read函数,而File_Read函数正调用了Win32的ReadFile函数,Seek函数指针对应Win32的SetFilePointer,7z这样做非常高明,这样7z的结构体不但有数据成员,同时也通过函数指针拥有了函数成员,达到了和c++相同的面向对象的功能,又通过宏判断以适应X86,Arm等平台和编译器。
假如我们首先获取了全部数据指针char* pAllData和数据长度iLength,用memcpy代替File_Read,用自动位置的代替File_Seek不就实现了不用CreateFileA打开文件,直接解压的目的了吗? 这个想法理论上是成立的,我在修改中也遇到了不少问题。首先ReadFile函数用memcpy来代替是可以的,但ReadFile不但读取了数据,也同时改变了HANDLE文件的位置(Seek的偏移),所以需要一个全局的位置,记住文件的偏移。我建立了func.h和func.c文件,里面定义了一些全局变量和修改过的函数。
#ifndef FUNC_H#define FUNC_H#ifndef kChunkSizeMax #define kChunkSizeMax (1 << 22)#endif#include "7zFile.h"#include "Types.h"extern char* g_pAllData;extern DWORD g_iAllDataLength;extern DWORD g_iSeekPos;extern HANDLE* g_handle;void g_func_GetLowAndHeightFromDWORD(DWORD v, DWORD* iLow, LONG *iHeight);UInt64 g_func_GetDWORDByLowAndHight(DWORD sizeLow,DWORD sizeHigh);WRes g_func_File_Close(CSzFile *p);WRes g_func_File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);WRes g_func_File_Read(CSzFile *p, void *data, size_t *size);#endif // FUNC_H
最关键的是这两个
WRes g_func_File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);WRes g_func_File_Read(CSzFile *p, void *data, size_t *size);我们要用这两个函数分别替换File_Seek和File_Read函数,才能达到去除文件HANDLE,内存直接解压的目的。g_ISeekPos是全局的文件指针偏移
我是先拿File_Read函数开刀,下面是关键的函数替换修改点(7zFile.c):
static SRes FileInStream_Read(void *pp, void *buf, size_t *size){ CFileInStream *p = (CFileInStream *)pp; //return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; return (g_func_File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ; //return SZ_OK;}static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin){ CFileInStream *p = (CFileInStream *)pp; //return File_Seek(&p->file, pos, origin); return g_func_File_Seek(&p->file, pos, origin);}这样,7z真实的Read和Seek函数便到了我们控制的函数里。
WRes g_func_File_Read(CSzFile *p, void *data, size_t *size){ size_t originalSize = *size; if (originalSize == 0) return 0; *size = 0; do { DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize; DWORD processed = 0; DWORD iCurrentPos = 0; UInt64 iSeekPos = 0; //BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL); //获取当前文件指针位置 ////iCurrentPos = SetFilePointer(*g_handle,NULL, NULL, FILE_CURRENT); //memcpy(data,g_pAllData+iCurrentPos,curSize); memcpy(data,g_pAllData+g_iSeekPos,curSize); processed = curSize; data = (void *)((Byte *)data + processed); originalSize -= processed; *size += processed; iSeekPos = (UInt64)processed; g_func_File_Seek(p,&iSeekPos,SZ_SEEK_CUR); if (processed == 0) break; } while (originalSize > 0); return 0;}
真实的Read函数里直接用memcpy代替ReadFile函数,实现内存拷贝功能
WRes g_func_File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin){ LARGE_INTEGER value; DWORD moveMethod; DWORD iCurrentPos = 0;// Int64 zzz; value.LowPart = (DWORD)*pos; value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16);// zzz = *pos; switch (origin) { case SZ_SEEK_SET: moveMethod = FILE_BEGIN;g_iSeekPos=(DWORD)(*pos);break; case SZ_SEEK_CUR: moveMethod = FILE_CURRENT;g_iSeekPos+=(DWORD)(*pos);break; case SZ_SEEK_END: moveMethod = FILE_END;g_iSeekPos=g_iAllDataLength;break; default: return ERROR_INVALID_PARAMETER; } //value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod); //iCurrentPos = SetFilePointer(*g_handle,NULL, NULL, FILE_CURRENT); //printf("XXOK--iCurrentPos:%d--g_iSeekPos:%d\n",iCurrentPos,g_iSeekPos); //g_iSeekPos = iCurrentPos;// if (value.LowPart == 0xFFFFFFFF)// {// WRes res = GetLastError();// if (res != NO_ERROR)// return res;// } *pos = g_iSeekPos; //*pos = ((Int64)value.HighPart << 32) | value.LowPart; //printf("--zzz:%d--*pos:%d\n",zzz,*pos); return 0;}真实的Seek函数直接用g_iSeekPos代替SetFilePointer,注意读取文件数据到内存的同时,文件偏移也变了,所以在
WRes g_func_File_Read(CSzFile *p, void *data, size_t *size)里有这么一句
而对于获取文件大小的File_GetLength函数,则直接赋值即可。
WRes File_GetLength(CSzFile *p, UInt64 *length){ #ifdef USE_WINDOWS_FILE *length = (UInt64)g_iAllDataLength; return 0;/* DWORD sizeHigh; DWORD sizeLow = GetFileSize(p->handle, &sizeHigh); if (sizeLow == 0xFFFFFFFF) { DWORD res = GetLastError(); if (res != NO_ERROR) return res; } *length = (((UInt64)sizeHigh) << 32) + sizeLow; return 0;*/ #else long pos = ftell(p->file); int res = fseek(p->file, 0, SEEK_END); *length = ftell(p->file); fseek(p->file, pos, SEEK_SET); return res; #endif}
通过这节的大刀阔斧的修改、增加源码,lib7z解压原理已经很清楚了,修改也已完毕,下一节就让我们试试吧。
- 2、lib7z-Memory从内存或网络解压数据(分析源码,修改源码)
- 1、lib7z-Memory从内存或网络解压数据(编译源码、前期准备)
- 3、lib7z-Memory从内存或网络解压数据(7z内存解压完成)
- 内存管理--page.s memory.c源码分析
- OS X内存管理:从源码进行分析(一)
- Objective-C内存管理:从源码进行分析(二)
- python源码分析----内存分配(2)
- jQuery源码分析-----CallBacks--memory
- memcached源码分析(五):数据保存及内存管理
- Jquery源码分析(修改)
- Vue学习之源码分析--从Vue.js源码角度再看数据绑定(三)
- 从源码分析IntentService
- 从源码分析 HashMap
- 从源码分析AsyncTask
- IntentService 从源码分析
- linux内存源码分析
- linux内存源码分析
- linux 0.11源码 内存管理 memory.c
- java线程初探
- WebSocket 和 Socket 的区别
- 存储过程
- 算法之乐:一个算法解决3道经典二叉树面试题(深度、长度、直径)
- android volley封装及源码解析
- 2、lib7z-Memory从内存或网络解压数据(分析源码,修改源码)
- 【原创】有向图的搜索
- cocoa pods的安装与使用
- Intel Code Challenge Final Round (Div. 1 + Div. 2, Combined) C. Ray Tracing
- Linux内存管理之mmap详解
- Java 中 synchronized的用法详解(四种用法)
- 两个链表的第一个公共结点
- TensorFlow之深入理解Neural Style
- 链表简述