|  | 
| 弄了个小程序。代码如下。 
 可以直接提取iso中文件,要求是ISO9660格式。复制代码#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;
}
注意,输出的LBA是2048字节大扇区式的LBA。
 如果只需要LBA和长度的话,还可以再改。
 
 VC2005编译并测试通过。
 
 
 用静态库编译,应该到哪都可以用了。
 
 | 
 |