|
弄了个小程序。代码如下。
- #include <stdio.h>
- #include <tchar.h>
- #include <locale.h>
- #include <tchar.h>
- #include <string>
- #include <vector>
- #include <mbstring.h>
- #include <stdlib.h>
- using namespace std;
- #ifdef _UNICODE
- typedef wstring _tstring;
- #else
- typedef string _tstring;
- #endif
- #define ATAPI_SECTOR_SIZE 2048 //一个CD扇区2048Byte
- #define LBA_TO_BYTE(x) (x*ATAPI_SECTOR_SIZE)
- //用法isodr.exe <iso文件> <光盘内路径> <输出路径>
- //例:isodr.exe C:\abc.iso /boot/boot.sdi C:\abc.tmp
- //例:isodr.exe C:\abc.iso /bootmgr C:\bootmgr //输出根目录下的bootmgr
- //直接运行程序显示本帮助。
- struct FILE_ITEM{
- unsigned long lba;
- string FileName;
- unsigned long size;
- };
- int _t_real_main(int argc, _TCHAR* argv[]);
- int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound);
- int _tmain(int argc, _TCHAR* argv[])
- {
- _TCHAR *help_txt = _T("ISO文件直接读取工具\t作者:sunsea\t参考网上部分代码改编而成\n高歌酹酒,来者相候,唤我今日,长缨在手。\n\n用法isodr.exe <iso文件> <光盘内路径> <输出路径>\n例:isodr.exe C:\\abc.iso /boot/boot.sdi C:\\abc.tmp\n例:isodr.exe C:\\abc.iso /bootmgr C:\\bootmgr 输出根目录下的bootmgr\n\n直接运行程序显示本帮助。");
- setlocale(LC_ALL,"chs");
- if (argc==1) {
- _tprintf(help_txt);
- }
- if (argc>1){
- return _t_real_main(argc,argv);
- }
- return 0;
- }
- inline size_t seek_and_read(FILE* file,void* buf,unsigned long offest,unsigned long length){
- fseek(file,offest,SEEK_SET);
- return fread(buf,length,1,file);
- }
- int _t_real_main(int argc, _TCHAR* argv[]){
- //这里是真正做事情的代码。
- //先检查源文件是否存在。
- _TCHAR *source_filename=argv[1];
- FILE * source_iso=NULL;
- FILE_ITEM myFile;//目标文件
- source_iso=_tfopen(source_filename,_T("rb"));
- if (source_iso==NULL)
- {
- _ftprintf(stderr,_T("源ISO镜像打开失败!请检查文件。"));
- return -1;
- }
- FILE *output=_tfopen(argv[3],_T("wb"));
- if (output==NULL){
- _ftprintf(stderr,_T("目标文件打开失败!请检查文件。"));
- return -1;
- }
- char buf_sector_1[ATAPI_SECTOR_SIZE];
- /* iso的前32768字节被保留,检查CD001标志*/
- unsigned long lba = (0x8000 / 0x800); /*从0x8000的地方开始寻找.*/
- for(;;++lba)
- {
- //ISO9660最大允许整个iso 2G大小。
- if(!seek_and_read(source_iso,buf_sector_1,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE)) { //读一个扇区
- _ftprintf(stderr,_T("源ISO镜像读取错误!请检查文件。"));
- return -1;
- }
- /*Identifier is always "CD001".*/
- if(buf_sector_1[1] != 'C' ||
- buf_sector_1[2] != 'D' ||
- buf_sector_1[3] != '0' ||
- buf_sector_1[4] != '0' ||
- buf_sector_1[5] != '1' ) /*判断CD001 不符合直接返回.*/
- {
- _ftprintf(stderr,_T("源ISO镜像非法!"));
- return -1;
- }
- if(buf_sector_1[0] == 0xff) /*Volume Descriptor Set Terminator.*/
- return -1; /*如果这是最后一个 也返回.*/
- if(buf_sector_1[0] != 0x01 /*Primary Volume Descriptor.*/)
- continue; /*不是Primary Volume Descriptor就继续*/
- /*Directory entry for the root directory.*/
- if(buf_sector_1[156] != 0x22 /*Msut 34.*/)
- return -1;
- /*Location of extent (LBA) in both-endian format.*/
- lba = *(unsigned long *)(buf_sector_1 + 156 + 2);
- break; /*读LBA,跳出.*/
- }
- //分析文件名。分解出目录
- string Temp;
- vector<string> WantedFileName;
- char *token = NULL;
- char *next_token = NULL;
- char *Wanted;
- bool isfound=false;
- #ifdef _UNICODE
- int need=0;
- need=wcstombs(NULL,argv[2],0)+1;
- Wanted = new char[need];
- wcstombs(Wanted,argv[2],need);
- #else
- Wanted = new char[strlen(argv[1])+1];
- strcpy(Wanted,argv[1]);
- #endif
- token=strtok_s(Wanted,"/",&next_token);
-
- while (token != NULL)
- {
- if (token != NULL)
- {
- Temp=token;
- WantedFileName.push_back(Temp);
- token = strtok_s(NULL,"/", &next_token);
-
- }
- }
- delete [] Wanted;//切分完毕
- PraseFileSystemAndFind(source_iso,lba,myFile,0,WantedFileName,isfound);
- if (!isfound){
- _ftprintf(stderr,_T("没找到你要的文件!"));
- }else{
- _tprintf(_T("找到目标文件,大小%d,LBA %d\n"),myFile.size,myFile.lba);
- fseek(source_iso,LBA_TO_BYTE(myFile.lba),SEEK_SET);
- char buffer[4096]; //按4K一块
- for (unsigned int i=0;i<=(myFile.size/4096);i++){
- if (i==(myFile.size/4096)){
- //最后一块
- fread(buffer,myFile.size-i*4096,1,source_iso);
- fwrite(buffer,myFile.size-i*4096,1,output);
- _tprintf(_T("输出完毕。"));
- }else{
- fread(buffer,4096,1,source_iso);
- fwrite(buffer,4096,1,output);
- }
- }
- }
- fclose(output);
- fclose(source_iso);
- if (!isfound){
- _tremove(argv[3]);
- }
-
- return 0;
- }
- int PraseFileSystemAndFind(FILE* isofile,unsigned long lba,FILE_ITEM &item,int depth,const vector<string> &NeedFileName,bool &isfound){
-
- isfound=false;
- char SectorBuf[ATAPI_SECTOR_SIZE];
- seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);
- unsigned long offset = 0; /*要读的文件(夹)的信息结构的偏移.*/
- bool isDir = 0; /*是否是文件夹.*/
- bool needRead = 0; /*需不需要重新读.*/
- for(;;offset += SectorBuf[offset + 0x0] /*Length of Directory Record.*/)
- {
- while(offset >= ATAPI_SECTOR_SIZE)
- {
- offset -= ATAPI_SECTOR_SIZE;
- ++lba;
- needRead = 1;
- /*Read again.*/
- } /*偏移超出这个扇区的范围就修正一下.*/
- if(needRead)
- seek_and_read(isofile,SectorBuf,LBA_TO_BYTE(lba),ATAPI_SECTOR_SIZE);
- needRead = 0;
-
- if(SectorBuf[offset + 0x0] == 0x0) /*No more.*/
- break; /*大小是0说明结束了,退出.*/
-
- /*Location of extent (LBA) in both-endian format.*/
- unsigned long fileLBA = *(unsigned long *)(SectorBuf + offset + 0x2);
- if(fileLBA <= lba)
- continue; /*获取文件LBA,小于就继续吧.*/
-
- isDir = SectorBuf[offset + 25] & 0x2; /*Is it a dir?*/
-
- unsigned long filesize = *(unsigned long *)(SectorBuf + offset + 10);
-
- /*Length of file identifier (file name).
- * This terminates with a ';' character
- * followed by the file ID number in ASCII coded decimal ('1').*/
- unsigned long filenameLength = SectorBuf[offset + 32];
- //if(!isDir) /*如果是文件就要删掉最后的";1".*/
- // filenameLength -= 2; /*Remove ';' and '1'.*/
-
- char *filename =new char[filenameLength + 1]; /*Add 1 for '\0'.*/
- memcpy(filename,
- (const void *)(SectorBuf + offset + 33),
- filenameLength); /*把文件名复制过来.*/
-
- if((!isDir) && (filename[0] == '_'))
- filename[0] = '.';
- if((!isDir) && (filename[filenameLength - 1] == '.'))
- filename[filenameLength - 1] = '\0';
- else
- filename[filenameLength] = '\0'; /*做一些修正.*/
- string _filename_safe = filename;
- delete [] filename;
- if(!isDir)
- {
- if(filesize != 0)
- {
- if (!stricmp(NeedFileName[depth].c_str(),_filename_safe.c_str())) //找到了!
- {
- item.FileName=_filename_safe;
- item.lba=fileLBA;
- item.size=filesize;
- isfound=true;
- return 1;
- }
- }
- }
- else
- {
- if (!stricmp(NeedFileName[depth].c_str(),_filename_safe.c_str()))
- PraseFileSystemAndFind(isofile,fileLBA,item,depth+1,NeedFileName,isfound); /*对的就递归.*/
- }
- }
-
- return 0;
- }
复制代码 可以直接提取iso中文件,要求是ISO9660格式。
注意,输出的LBA是2048字节大扇区式的LBA。
如果只需要LBA和长度的话,还可以再改。
VC2005编译并测试通过。
用静态库编译,应该到哪都可以用了。
|
|