VC资源文件版本解析类: (2) 源文件

来源:岁月联盟 编辑:exp 时间:2011-09-02

1#include "rcversion.h"
  2#include "../mysdk/common/c_ex_api.h"
  3#include "../mysdk/common/macro.h"
  4#include <algorithm>
  5#include <cstring>
  6#include <cassert>
  7using namespace std;
  8
  9CRCVersion::CRCVersion():
 10m_hFile(INVALID_HANDLE_VALUE)
 11,m_ullFileVer(0)
 12,m_ullProductVer(0)
 13,m_ullOtherFileVer(0)
 14,m_ullOtherProductVer(0)
 15{
 16}
 17
 18/// 打开资源文件,后缀名为.rc
 19bool CRCVersion::Open(LPCTSTR lpRCFile)
 20{
 21  const TCHAR* pExt = _tcsstr(lpRCFile,_T(".rc"));
 22    if (NULL == pExt) return false;
 23
 24    m_hFile = CreateFile(lpRCFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
 25                        FILE_ATTRIBUTE_NORMAL,NULL);
 26    if (INVALID_HANDLE_VALUE==m_hFile)
 27        return false;
 28
 29  m_tstrFileName = lpRCFile;    ParseRC();
 30    return true;
 31}
 32/// 保存文件,先保存到一个临时文件,再拷贝覆盖到原文件
 33bool CRCVersion::Save()
 34{
 35    tstring tstrTempFile = m_tstrFileName + _T(".tmp");
 36    HANDLE hTempFile = CreateFile(tstrTempFile.c_str(),GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
 37                       FILE_ATTRIBUTE_NORMAL,NULL);
 38  if (INVALID_HANDLE_VALUE == hTempFile)
 39        return false;
 40   
 41    SaveContent(hTempFile);
 42    Close();
 43
 44    CloseHandle(hTempFile);
 45    DWORD dwFlag = GetFileAttributes(m_tstrFileName.c_str());
 46    dwFlag &= ~FILE_ATTRIBUTE_READONLY;
 47    SetFileAttributes(m_tstrFileName.c_str(),dwFlag);
 48    DeleteFile(m_tstrFileName.c_str());
 49    MoveFile(tstrTempFile.c_str(),m_tstrFileName.c_str());
 50    DeleteFile(tstrTempFile.c_str());
 51}
 52// 关闭文件
 53void CRCVersion::Close()
 54{
 55  if (INVALID_HANDLE_VALUE != m_hFile)
 56    {
 57        CloseHandle(m_hFile);
 58        m_hFile = INVALID_HANDLE_VALUE;
 59    }
 60}
 61
 62void CRCVersion::SaveContent(HANDLE hFile)
 63{
 64    assert(INVALID_HANDLE_VALUE != hFile);
 65   
 66  DWORD dwWrite, dwWrited;
 67    char  buf[2];
 68    if (UNICODE_BIG == m_nCharEncodeType)
 69    {
 70        memcpy(buf,"/xfe/xff",2);
 71        dwWrite = 2;
 72    }
 73    else if (UNICODE_LITTLE == m_nCharEncodeType)
 74    {
 75        memcpy(buf,"/xff/xfe",2);
 76        dwWrite = 2;
 77    }
 78    else
 79    {
 80        dwWrite = 0;
 81    }
 82    WriteFile(hFile,buf,dwWrite,&dwWrited,NULL);
 83
 84    for (string strLine;!eof();strLine.clear())
 85    {
 86        getline(strLine);
 87        ChangeLine(strLine);
 88        if (ANSI != m_nCharEncodeType)
 89        {
 90            wstring wstrLine;
 91            astr2wstr(strLine.c_str(),wstrLine);
 92            if ((is_big_endian() ^ (UNICODE_BIG==m_nCharEncodeType)))
 93            {
 94                for (const wchar_t* pwc = wstrLine.c_str();*pwc != L'/0';++pwc)
 95                {
 96                    char* pH = (char*)pwc;
 97                    char* pL = (char*)(pH+1);
 98                    swap(*pH,*pL);
 99                }
100            }
101            WriteFile(hFile,wstrLine.c_str(),wstrLine.length()*sizeof(wchar_t),&dwWrited,NULL);
102        }
103        else
104        {
105        WriteFile(hFile,strLine.c_str(),strLine.length()*sizeof(char),&dwWrited,NULL);
106        }
107    }
108}
109
110void CRCVersion::ChangeLine(string& strLine)
111{
112    string strVal;  size_t pos;
113  string strReplace;
114  ULONGLONG ullVer;
115
116    if ((pos = ParseVersionInfo(strLine,"FILEVERSION",strVal)) != string::npos)
117    {
118        GetVersion(&ullVer,NULL);
119        strReplace = VerToStrA(ullVer,',');
120    }
121    else if ((pos = ParseVersionInfo(strLine,"PRODUCTVERSION",strVal)) != string::npos)
122    {
123        GetVersion(NULL,&ullVer);
124        strReplace = VerToStrA(ullVer,',');
125    }
126    else if ((pos = ParseBlockInfo(strLine,"VALUE /"CompanyName/"",strVal)) != string::npos)
127    {
128        tstr2astr(m_tstrCompanyName,strReplace);
129    }
130    else if ((pos = ParseBlockInfo(strLine,"VALUE /"FileDescription/"",strVal))!=string::npos)
131    {
132        tstr2astr(m_tstrFileDesc,strReplace);
133    }
134    else if ((pos = ParseBlockInfo(strLine,"VALUE /"FileVersion/"",strVal))!=string::npos)
135    {
136        GetOtherVersion(&ullVer,NULL);
137        strReplace = VerToStrA(ullVer);
138    }
139    else if ((pos = ParseBlockInfo(strLine,"VALUE /"InternalName/"",strVal))!=string::npos)
140    {
141        tstr2astr(m_tstrInternalName,strReplace);
142    }
143    else if ((pos = ParseBlockInfo(strLine,"VALUE /"LegalCopyright/"",strVal))!=string::npos)
144    {
145        tstr2astr(m_tstrCopyright,strReplace);
146    }
147    else if ((pos = ParseBlockInfo(strLine,"VALUE /"OriginalFilename/"",strVal))!=string::npos)
148    {
149        tstr2astr(m_tstrOriginalFileName,strReplace);
150    }
151    else if ((pos = ParseBlockInfo(strLine,"VALUE /"ProductName/"",strVal))!=string::npos)
152    {
153        tstr2astr(m_tstrProductName,strReplace);
154    }
155    else if ((pos = ParseBlockInfo(strLine,"VALUE /"ProductVersion/"",strVal))!=string::npos)
156    {
157        GetOtherVersion(NULL,&ullVer);
158        strReplace = VerToStrA(ullVer);
159    }
160    if (pos != string::npos)
161    {
162        strLine.replace(pos,strVal.length(),strReplace);
163    }
164}
165
166/// 解析文件
167void CRCVersion::ParseRC()
168{
169    assert(INVALID_HANDLE_VALUE != m_hFile);
170    ParseCharEncode();
171    ParseContent();
172}
173
174/// 读头2个字节,获取字符集编码类型
175void CRCVersion::ParseCharEncode()
176{
177    char buf[2];    DWORD dwReaded;
178    if (ReadFile(m_hFile,buf,sizeof(buf),&dwReaded,0) && sizeof(buf) == dwReaded)
179    {
180        if (buf[0]==(char)0xFF && buf[1]==(char)0xFE)
181        {
182            m_nCharEncodeType = UNICODE_LITTLE;
183        }
184        else if (buf[0]==(char)0xFE && buf[1]==(char)0xFF)
185        {
186            m_nCharEncodeType = UNICODE_BIG;
187        }
188        else
189        {
190            m_nCharEncodeType = ANSI;
191            SetFilePointer(m_hFile,0,NULL,FILE_BEGIN);
192        }
193    }
194    else
195    {
196        m_nCharEncodeType = UNKNOW;
197    }
198}
199
200/**//// 逐次按行读取,解析文件的内容
201void CRCVersion::ParseContent()
202{
203  for (string strLine;!eof();strLine.clear())
204  {
205        getline(strLine);
206    ParseLine(strLine);
207  }
208    if (ANSI == m_nCharEncodeType)
209       SetFilePointer(m_hFile,0,NULL,FILE_BEGIN);
210    else
211     SetFilePointer(m_hFile,2,NULL,FILE_BEGIN);
212}
213
214/**//// 解析单行,提取文件版本、产品版本、公司名称、文件描述、文件版本、内部名称、版权信息、源文件名、产品名称
215void CRCVersion::ParseLine(string& strLine)
216{
217    string strVal;
218    if (ParseVersionInfo(strLine,"FILEVERSION",strVal)!=string::npos)
219    {
220        m_ullFileVer = StrToVerA(strVal,',');
221    }
222    else if (ParseVersionInfo(strLine,"PRODUCTVERSION",strVal)!=string::npos)
223    {
224        m_ullProductVer = StrToVerA(strVal,',');
225    }
226    else if (ParseBlockInfo(strLine,"VALUE /"CompanyName/"",strVal)!=string::npos)
227    {
228        astr2tstr(strVal.c_str(),m_tstrCompanyName);
229    }
230    else if (ParseBlockInfo(strLine,"VALUE /"FileDescription/"",strVal)!=string::npos)
231    {
232        astr2tstr(strVal.c_str(),m_tstrFileDesc);
233    }
234    else if (ParseBlockInfo(strLine,"VALUE /"FileVersion/"",strVal)!=string::npos)
235    {
236        m_ullOtherFileVer = StrToVerA(strVal);
237    }
238    else if (ParseBlockInfo(strLine,"VALUE /"InternalName/"",strVal)!=string::npos)
239    {
240        astr2tstr(strVal.c_str(),m_tstrInternalName);
241    }
242    else if (ParseBlockInfo(strLine,"VALUE /"LegalCopyright/"",strVal)!=string::npos)
243    {
244        astr2tstr(strVal.c_str(),m_tstrCopyright);
245    }
246    else if (ParseBlockInfo(strLine,"VALUE /"OriginalFilename/"",strVal)!=string::npos)
247    {
248        astr2tstr(strVal.c_str(),m_tstrOriginalFileName);
249    }
250    else if (ParseBlockInfo(strLine,"VALUE /"ProductName/"",strVal)!=string::npos)
251    {
252        astr2tstr(strVal.c_str(),m_tstrProductName);
253    }
254    else if (ParseBlockInfo(strLine,"VALUE /"ProductVersion/"",strVal)!=string::npos)
255    {
256        m_ullOtherProductVer = StrToVerA(strVal);
257    }
258}
259
260size_t CRCVersion::ParseVersionInfo(const string& strLine,const string& strType,string& strVal)
261{
262    size_t pos = strLine.find(strType);
263    if (pos == string::npos)
264    {
265        return string::npos;
266    }
267    pos += strType.length();
268    pos = strLine.find(',',pos);
269    if (pos == string::npos)
270    {
271        return string::npos;
272    }
273    size_t pos3 = pos;
274    size_t pos1 = strLine.rfind(' ',pos);
275    size_t pos2 = strLine.rfind('/t',pos);
276    if (pos1 == string::npos && pos2 == string::npos)
277    {
278        return string::npos;
279    }
280    else if (pos1 == string::npos || pos2 == string::npos)
281    {
282        pos = min(pos1, pos2);
283    }
284    else
285    {
286        pos = max(pos1, pos2);
287    }
288    pos2 = ++pos;
289    pos = strLine.find(',', ++pos3);
290    if (pos == string::npos)
291    {
292        return string::npos;
293    }
294    pos = strLine.find(',',++pos);
295    if (pos == string::npos)
296    {
297        return string::npos;
298    }
299    pos1 = ++pos;
300    pos  = strLine.find(' ',pos1);
301    if (pos == string::npos)
302    {
303        pos = strLine.find('/t',pos1);
304    }
305    if (pos == string::npos)
306    {
307        pos = strLine.find('/r',pos1);
308    }
309    if (pos == string::npos)
310    {
311        pos = strLine.find('/n',pos1);
312    }
313    if (pos == string::npos)
314    {
315        return string::npos;
316    }
317    strVal = strLine.substr(pos2,pos-pos2);
318    return pos2;
319}
320
321size_t CRCVersion::ParseBlockInfo(const string& strLine,const string& strType,string& strVal)
322{
323    size_t pos = strLine.find(strType);
324    if (pos == string::npos)
325    {
326        return string::npos;
327    }
328    pos += strType.length();
329    pos = strLine.find(',',pos);
330    if (pos == string::npos)
331    {
332        return string::npos;
333    }
334    pos = strLine.find('/"',++pos);
335    if (pos == string::npos)
336    {
337        return string::npos;
338    }
339    size_t pos1 = ++pos;
340    pos = strLine.rfind('/"');
341    if (pos == string::npos)
342    {
343        return string::npos;
344    }
345    strVal = strLine.substr(pos1,pos-pos1);
346    return pos1;
347}
348/**//// 使用字节数判断是否到达文件末尾
349bool CRCVersion::eof() const
350{
351   assert(INVALID_HANDLE_VALUE != m_hFile);
352   DWORD dwCurLow = SetFilePointer(m_hFile,0,NULL,FILE_CURRENT);
353   DWORD dwEndLow = SetFilePointer(m_hFile,0,NULL,FILE_END);
354   bool bEof = (dwCurLow == dwEndLow);
355   SetFilePointer(m_hFile,dwCurLow,NULL,FILE_BEGIN);
356   return bEof;
357}
358/**//// 获取每行的文本
359void CRCVersion::getline(string& strLine) const
360{
361   assert(UNKNOW != m_nCharEncodeType);
362
363   char buf[2] = {'/0'};   wstring wstrLine;
364   for (DWORD dwRead,dwReaded;;)
365   {
366       dwRead = (ANSI == m_nCharEncodeType ? 1 : 2);
367       if (!ReadFile(m_hFile,buf,dwRead,&dwReaded,NULL)||0==dwReaded)
368       {
369           break;
370       }
371       if (1==dwReaded)
372       {
373           strLine += buf[0];
374       if (buf[0]=='/r')
375           {
376               if (!ReadFile(m_hFile,&buf[1],1,&dwReaded,NULL)||0==dwReaded)
377               {
378                   break;
379               }
380         if (buf[1]=='/n')
381               {
382                   strLine += buf[1];
383               }
384               else
385               {
386           SetFilePointer(m_hFile,-1,NULL,FILE_CURRENT);
387               }
388               break;
389           }
390           else if (buf[0]=='/n')
391           {
392               break;
393           }
394       }
395       else
396       {
397      if ((is_big_endian() ^ (UNICODE_BIG==m_nCharEncodeType)))
398          {
399         swap(buf[0],buf[1]);
400          }
401          wchar_t wch;   memcpy(&wch,buf,sizeof(wchar_t));
402          wstrLine += wch;
403          if (wch==L'/r')
404          {
405              if (!ReadFile(m_hFile,buf,2,&dwReaded,NULL)||0==dwReaded)
406              {
407                  break;
408              }
409              if ((is_big_endian() ^ (UNICODE_BIG==m_nCharEncodeType)))
410              {
411                  swap(buf[0],buf[1]);
412              }
413              memcpy(&wch,buf,sizeof(wchar_t));
414              if (wch==L'/n')
415              {
416                  wstrLine += wch;
417              }
418              else
419              {
420                  SetFilePointer(m_hFile,-2,NULL,FILE_CURRENT);
421              }
422              break;
423          }
424          else if (wch==L'/n')
425          {
426              break;
427          }
428       }
429   }
430   if (ANSI != m_nCharEncodeType)
431   {
432       wstr2astr(wstrLine.c_str(),strLine);
433       TRACE4(L"%s",wstrLine.c_str());
434   }
435   else
436   {
437       TRACE4("%s",strLine.c_str());
438   }
439}
440
441/**///////////////////////////////////////////////////////////////////////////
442const tstring& CRCVersion::GetCompanyName() const
443{
444    return m_tstrCompanyName;
445}
446
447const tstring& CRCVersion::GetProductName() const
448{
449    return m_tstrProductName;
450}
451
452const tstring& CRCVersion::GetCopyright() const
453{
454    return m_tstrCopyright;
455}
456
457const tstring& CRCVersion::GetFileDesc() const
458{
459    return m_tstrFileDesc;
460}
461
462const tstring& CRCVersion::GetInternalName() const
463{
464    return m_tstrInternalName;
465}
466
467const tstring& CRCVersion::GetOriginalFilename() const
468{
469    return m_tstrOriginalFileName;
470}
471
472void CRCVersion::GetVersion(ULONGLONG* pullFileVer,ULONGLONG* pullProductVer) const
473{
474    if (pullFileVer)    *pullFileVer = m_ullFileVer;
475    if (pullProductVer) *pullProductVer = m_ullProductVer;
476}
477
478void CRCVersion::GetOtherVersion(ULONGLONG* pullFileVer,ULONGLONG* pullProductVer) const
479{
480    if (pullFileVer)    *pullFileVer = m_ullOtherFileVer;
481    if (pullProductVer) *pullProductVer = m_ullOtherProductVer;
482}
483
484void CRCVersion::GetFileVer(ULONG* pulHigh,ULONG* pulLow) const
485{
486    if (pulHigh) *pulHigh = m_ullFileVer >> 32;
487    if (pulLow)  *pulLow  = m_ullFileVer & 0x00000000FFFFFFFF;
488}
489
490void CRCVersion::GetProductVer(ULONG* pulHigh,ULONG* pulLow) const
491{
492    if (pulHigh) *pulHigh = m_ullFileVer >> 32;
493    if (pulLow)  *pulLow  = m_ullFileVer & 0x00000000FFFFFFFF;
494}
495
496void CRCVersion::GetOtherFileVer(ULONG* pulHigh,ULONG* pulLow) const
497{
498    if (pulHigh) *pulHigh = m_ullOtherFileVer >> 32;
499    if (pulLow)  *pulLow  = m_ullOtherFileVer & 0x00000000FFFFFFFF;
500}
501
502void CRCVersion::GetOtherProductVer(ULONG* pulHigh,ULONG* pulLow) const
503{
504    if (pulHigh) *pulHigh = m_ullOtherProductVer >> 32;
505    if (pulLow)  *pulLow  = m_ullOtherProductVer & 0x00000000FFFFFFFF;
506}
507
508/**///////////////////////////////////////////////////////////////////////////
509void CRCVersion::SetCompanyName(const tstring& tstrCompanyName)
510{
511    m_tstrCompanyName = tstrCompanyName;
512}
513
514void CRCVersion::SetProductName(const tstring& tstrProductName)
515{
516    m_tstrProductName = tstrProductName;
517}
518
519void CRCVersion::SetCopyright(const tstring& tstrCopyright)
520{
521    m_tstrCopyright = tstrCopyright;
522}
523
524void CRCVersion::SetFileDesc(const tstring& tstrFileDesc)
525{
526    m_tstrFileDesc = tstrFileDesc;
527}
528
529void CRCVersion::SetInternalName(const tstring& tstrInternalName)
530{
531    m_tstrInternalName = tstrInternalName;
532}
533
534void CRCVersion::SetOriginalFileName(const tstring& tstrOriginalFileName)
535{
536    m_tstrOriginalFileName = tstrOriginalFileName;
537}
538
539void CRCVersion::SetVersion(ULONGLONG* pullFileVer,ULONGLONG* pullProductVer)
540{
541    if (pullFileVer) m_ullFileVer = *pullFileVer;
542    if (pullProductVer) m_ullProductVer = *pullProductVer;
543}
544
545void CRCVersion::SetOtherVersion(ULONGLONG* pullFileVer,ULONGLONG* pullProductVer)
546{
547    if (pullFileVer)    m_ullOtherFileVer = *pullFileVer;
548    if (pullProductVer) m_ullOtherProductVer = *pullProductVer;
549}
550
551/**///////////////////////////////////////////////////////////////////////////
552string CRCVersion::VerToStrA(ULONGLONG ullVer,char sep /**//*='.'*/)
553{
554    ULONG ulHigh = ullVer >> 32;
555    ULONG ulLow  = ullVer & 0x00000000FFFFFFFF;
556    char  buf[32];
557    sprintf(buf,"%d%c%d%c%d%c%d",ulHigh>>16,sep,ulHigh&0x0000FFFF,sep,ulLow>>16,sep,ulLow&0x0000FFFF);
558  return buf;
559}
560
561wstring CRCVersion::VerToStrW(ULONGLONG ullVer,wchar_t wsep/**//*=L'.'*/)
562{
563    ULONG ulHigh = ullVer >> 32;
564    ULONG ulLow  = ullVer & 0x00000000FFFFFFFF;
565    wchar_t  buf[32];
566    swprintf(buf,L"%d%c%d%c%d%c%d",ulHigh>>16,wsep,ulHigh&0x0000FFFF,wsep,ulLow>>16,wsep,ulLow&0x0000FFFF);
567    return buf;
568}
569
570ULONGLONG CRCVersion::StrToVerA(const string& strVer,char sep /**//*='.'*/)
571{
572    long      a = 0, b = 0, c = 0, d = 0;
573    ULONGLONG ullVal = 0;
574
575    size_t pos, pos1, pos2;
576    pos = strVer.find(sep);
577    if (pos != string::npos)
578        a = atol(strVer.substr(0,pos).c_str());
579    pos1 = strVer.find(sep,pos+1);
580    if (pos1 != string::npos)
581        b = atol(strVer.substr(pos+1,pos1-pos-1).c_str());
582    pos2 = strVer.find(sep,pos1+1);
583    if (pos2 != string::npos)
584        c = atol(strVer.substr(pos1+1,pos2-pos1-1).c_str());
585    d = atol(strVer.substr(pos2+1).c_str());
586    ullVal = (((ULONGLONG)((a << 16) + b)) << 32) + (c << 16) + d;
587
588    return ullVal;
589}
590
591ULONGLONG CRCVersion::StrToVerW(const wstring& wstrVer,wchar_t wsep/**//*=L'.'*/)
592{
593    long      a = 0, b = 0, c = 0, d = 0;
594    ULONGLONG ullVal = 0;
595
596    size_t pos, pos1, pos2;
597    pos = wstrVer.find(wsep);
598    if (pos != string::npos)
599        a = _wtol(wstrVer.substr(0,pos).c_str());
600    pos1 = wstrVer.find(wsep,pos+1);
601    if (pos1 != string::npos)
602        b = _wtol(wstrVer.substr(pos+1,pos1-pos-1).c_str());
603    pos2 = wstrVer.find(wsep,pos1+1);
604    if (pos2 != string::npos)
605        c = _wtol(wstrVer.substr(pos1+1,pos2-pos1-1).c_str());
606    d = _wtol(wstrVer.substr(pos2+1).c_str());
607    ullVal = (((ULONGLONG)((a << 16) + b)) << 32) + (c << 16) + d;
608
609    return ullVal;
610}

作者“天道酬勤”