VC资源文件版本解析类: (2) 源文件
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}
作者“天道酬勤”