PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/reporting/crashsender/FilePreviewCtrl.cpp

http://crashrpt.googlecode.com/
C++ | 2082 lines | 1554 code | 390 blank | 138 comment | 209 complexity | 355c48d945f55446df805f4aff8fc950 MD5 | raw file
Possible License(s): LGPL-3.0, BSD-3-Clause
  1. /*************************************************************************************
  2. This file is a part of CrashRpt library.
  3. Copyright (c) 2003-2013 The CrashRpt project authors. All Rights Reserved.
  4. Use of this source code is governed by a BSD-style license
  5. that can be found in the License.txt file in the root of the source
  6. tree. All contributing project authors may
  7. be found in the Authors.txt file in the root of the source tree.
  8. ***************************************************************************************/
  9. #include "stdafx.h"
  10. #include "FilePreviewCtrl.h"
  11. #include "png.h"
  12. #include "jpeglib.h"
  13. #include "strconv.h"
  14. #pragma warning(disable:4611)
  15. // DIBSIZE calculates the number of bytes required by an image
  16. #define WIDTHBYTES(bits) ((DWORD)(((bits)+31) & (~31)) / 8)
  17. #define DIBWIDTHBYTES(bi) (DWORD)WIDTHBYTES((DWORD)(bi).biWidth * (DWORD)(bi).biBitCount)
  18. #define _DIBSIZE(bi) (DIBWIDTHBYTES(bi) * (DWORD)(bi).biHeight)
  19. #define DIBSIZE(bi) ((bi).biHeight < 0 ? (-1)*(_DIBSIZE(bi)) : _DIBSIZE(bi))
  20. static inline
  21. unsigned char CLAMP(int x)
  22. {
  23. return (unsigned char)((x > 255) ? 255 : (x < 0) ? 0 : x);
  24. }
  25. //-----------------------------------------------------------------------------
  26. // CFileMemoryMapping implementation
  27. //-----------------------------------------------------------------------------
  28. CFileMemoryMapping::CFileMemoryMapping()
  29. {
  30. // Set member vars to the default values
  31. m_hFile = INVALID_HANDLE_VALUE;
  32. m_uFileLength = 0;
  33. m_hFileMapping = NULL;
  34. SYSTEM_INFO si;
  35. GetSystemInfo(&si);
  36. m_dwAllocGranularity = si.dwAllocationGranularity;
  37. }
  38. CFileMemoryMapping::~CFileMemoryMapping()
  39. {
  40. Destroy();
  41. }
  42. BOOL CFileMemoryMapping::Init(LPCTSTR szFileName)
  43. {
  44. if(m_hFile!=INVALID_HANDLE_VALUE)
  45. {
  46. // If a file mapping already created, destroy it
  47. Destroy();
  48. }
  49. // Open file handle
  50. m_hFile = CreateFile(szFileName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  51. if(m_hFile == INVALID_HANDLE_VALUE)
  52. return FALSE;
  53. // Create file mapping
  54. m_hFileMapping = CreateFileMapping(m_hFile, 0, PAGE_READONLY, 0, 0, 0);
  55. LARGE_INTEGER size;
  56. GetFileSizeEx(m_hFile, &size);
  57. m_uFileLength = size.QuadPart;
  58. return TRUE;
  59. }
  60. BOOL CFileMemoryMapping::Destroy()
  61. {
  62. // Unmap all views
  63. std::map<DWORD, LPBYTE>::iterator it;
  64. for(it=m_aViewStartPtrs.begin(); it!=m_aViewStartPtrs.end(); it++)
  65. {
  66. if(it->second != NULL)
  67. UnmapViewOfFile(it->second);
  68. }
  69. m_aViewStartPtrs.clear();
  70. // Close file mapping handle
  71. if(m_hFileMapping!=NULL)
  72. {
  73. CloseHandle(m_hFileMapping);
  74. }
  75. // Close file handle
  76. if(m_hFile!=INVALID_HANDLE_VALUE)
  77. {
  78. CloseHandle(m_hFile);
  79. }
  80. m_hFileMapping = NULL;
  81. m_hFile = INVALID_HANDLE_VALUE;
  82. m_uFileLength = 0;
  83. return TRUE;
  84. }
  85. ULONG64 CFileMemoryMapping::GetSize()
  86. {
  87. return m_uFileLength;
  88. }
  89. LPBYTE CFileMemoryMapping::CreateView(DWORD dwOffset, DWORD dwLength)
  90. {
  91. DWORD dwThreadId = GetCurrentThreadId();
  92. DWORD dwBaseOffs = dwOffset-dwOffset%m_dwAllocGranularity;
  93. DWORD dwDiff = dwOffset-dwBaseOffs;
  94. LPBYTE pPtr = NULL;
  95. CAutoLock lock(&m_csLock);
  96. std::map<DWORD, LPBYTE>::iterator it = m_aViewStartPtrs.find(dwThreadId);
  97. if(it!=m_aViewStartPtrs.end())
  98. {
  99. UnmapViewOfFile(it->second);
  100. }
  101. pPtr = (LPBYTE)MapViewOfFile(m_hFileMapping, FILE_MAP_READ, 0, dwBaseOffs, dwLength+dwDiff);
  102. if(it!=m_aViewStartPtrs.end())
  103. {
  104. it->second = pPtr;
  105. }
  106. else
  107. {
  108. m_aViewStartPtrs[dwThreadId] = pPtr;
  109. }
  110. return (pPtr+dwDiff);
  111. }
  112. CImage::CImage()
  113. {
  114. m_hBitmap = NULL;
  115. m_hPalette = NULL;
  116. m_bLoadCancelled = FALSE;
  117. }
  118. CImage::~CImage()
  119. {
  120. Destroy();
  121. }
  122. BOOL CImage::IsBitmap(FILE* f)
  123. {
  124. rewind(f);
  125. BITMAPFILEHEADER bfh;
  126. size_t n = fread(&bfh, sizeof(bfh), 1, f);
  127. if(n!=1)
  128. return FALSE;
  129. if(memcmp(&bfh.bfType, "BM", 2)!=0)
  130. return FALSE;
  131. return TRUE;
  132. }
  133. BOOL CImage::IsPNG(FILE* f)
  134. {
  135. png_byte header[8];
  136. rewind(f);
  137. fread(header, 1, 8, f);
  138. if(png_sig_cmp(header, 0, 8))
  139. return FALSE;
  140. return TRUE;
  141. }
  142. BOOL CImage::IsJPEG(FILE* f)
  143. {
  144. rewind(f);
  145. // Read first two bytes (SOI marker).
  146. // Each JPEG file begins with SOI marker (0xD8FF).
  147. WORD wSOIMarker;
  148. int n = (int)fread(&wSOIMarker, 1, 2, f);
  149. if(n!=2)
  150. return FALSE;
  151. if(wSOIMarker==0xD8FF)
  152. return TRUE; // This is a JPEG file
  153. return FALSE;
  154. }
  155. BOOL CImage::IsImageFile(CString sFileName)
  156. {
  157. FILE* f = NULL;
  158. _TFOPEN_S(f, sFileName.GetBuffer(0), _T("rb"));
  159. if(f==NULL)
  160. return FALSE;
  161. if(IsBitmap(f) || IsPNG(f) || IsJPEG(f))
  162. {
  163. fclose(f);
  164. return TRUE;
  165. }
  166. fclose(f);
  167. return FALSE;
  168. }
  169. void CImage::Destroy()
  170. {
  171. CAutoLock lock(&m_csLock);
  172. if(m_hBitmap)
  173. {
  174. DeleteObject(m_hBitmap);
  175. m_hBitmap = NULL;
  176. }
  177. if(m_hPalette)
  178. {
  179. DeleteObject(m_hPalette);
  180. m_hPalette = NULL;
  181. }
  182. m_bLoadCancelled = FALSE;
  183. }
  184. BOOL CImage::IsValid()
  185. {
  186. CAutoLock lock(&m_csLock);
  187. return m_hBitmap!=NULL;
  188. }
  189. BOOL CImage::Load(CString sFileName)
  190. {
  191. Destroy();
  192. FILE* f = NULL;
  193. _TFOPEN_S(f, sFileName.GetBuffer(0), _T("rb"));
  194. if(f==NULL)
  195. return FALSE;
  196. if(IsBitmap(f))
  197. {
  198. fclose(f);
  199. return LoadBitmapFromBMPFile(sFileName.GetBuffer(0));
  200. }
  201. else if(IsPNG(f))
  202. {
  203. fclose(f);
  204. return LoadBitmapFromPNGFile(sFileName.GetBuffer(0));
  205. }
  206. else if(IsJPEG(f))
  207. {
  208. fclose(f);
  209. return LoadBitmapFromJPEGFile(sFileName.GetBuffer(0));
  210. }
  211. fclose(f);
  212. return FALSE;
  213. }
  214. void CImage::Cancel()
  215. {
  216. CAutoLock lock(&m_csLock);
  217. m_bLoadCancelled = TRUE;
  218. }
  219. // The following code was taken from http://support.microsoft.com/kb/158898
  220. BOOL CImage::LoadBitmapFromBMPFile(LPTSTR szFileName)
  221. {
  222. CAutoLock lock(&m_csLock);
  223. BITMAP bm;
  224. // Use LoadImage() to get the image loaded into a DIBSection
  225. m_hBitmap = (HBITMAP)LoadImage( NULL, szFileName, IMAGE_BITMAP, 0, 0,
  226. LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
  227. if( m_hBitmap == NULL )
  228. return FALSE;
  229. // Get the color depth of the DIBSection
  230. GetObject(m_hBitmap, sizeof(BITMAP), &bm );
  231. // If the DIBSection is 256 color or less, it has a color table
  232. if( ( bm.bmBitsPixel * bm.bmPlanes ) <= 8 )
  233. {
  234. HDC hMemDC = NULL;
  235. HBITMAP hOldBitmap = NULL;
  236. RGBQUAD rgb[256];
  237. LPLOGPALETTE pLogPal = NULL;
  238. WORD i = 0;
  239. // Create a memory DC and select the DIBSection into it
  240. hMemDC = CreateCompatibleDC( NULL );
  241. hOldBitmap = (HBITMAP)SelectObject( hMemDC, m_hBitmap );
  242. // Get the DIBSection's color table
  243. GetDIBColorTable( hMemDC, 0, 256, rgb );
  244. // Create a palette from the color tabl
  245. pLogPal = (LOGPALETTE *)malloc( sizeof(LOGPALETTE) + (256*sizeof(PALETTEENTRY)) );
  246. pLogPal->palVersion = 0x300;
  247. pLogPal->palNumEntries = 256;
  248. for(i=0;i<256;i++)
  249. {
  250. pLogPal->palPalEntry[i].peRed = rgb[i].rgbRed;
  251. pLogPal->palPalEntry[i].peGreen = rgb[i].rgbGreen;
  252. pLogPal->palPalEntry[i].peBlue = rgb[i].rgbBlue;
  253. pLogPal->palPalEntry[i].peFlags = 0;
  254. }
  255. m_hPalette = CreatePalette( pLogPal );
  256. // Clean up
  257. free( pLogPal );
  258. SelectObject( hMemDC, hOldBitmap );
  259. DeleteDC( hMemDC );
  260. }
  261. else // It has no color table, so use a halftone palette
  262. {
  263. HDC hRefDC = NULL;
  264. hRefDC = GetDC( NULL );
  265. m_hPalette = CreateHalftonePalette( hRefDC );
  266. ReleaseDC( NULL, hRefDC );
  267. }
  268. return TRUE;
  269. }
  270. BOOL CImage::LoadBitmapFromPNGFile(LPTSTR szFileName)
  271. {
  272. BOOL bStatus = FALSE;
  273. FILE *fp = NULL;
  274. const int number = 8;
  275. png_byte header[number];
  276. png_structp png_ptr = NULL;
  277. png_infop info_ptr = NULL;
  278. png_infop end_info = NULL;
  279. png_uint_32 rowbytes = 0;
  280. png_uint_32 width = 0;
  281. png_uint_32 height = 0;
  282. png_bytep row = NULL;
  283. int y = 0;
  284. BITMAPINFO* pBMI = NULL;
  285. HDC hDC = NULL;
  286. _TFOPEN_S(fp, szFileName, _T("rb"));
  287. if (!fp)
  288. {
  289. return FALSE;
  290. }
  291. fread(header, 1, number, fp);
  292. if(png_sig_cmp(header, 0, number))
  293. {
  294. goto cleanup;
  295. }
  296. png_ptr = png_create_read_struct
  297. (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  298. if (!png_ptr)
  299. goto cleanup;
  300. if (setjmp(png_ptr->jmpbuf))
  301. goto cleanup;
  302. info_ptr = png_create_info_struct(png_ptr);
  303. if (!info_ptr)
  304. goto cleanup;
  305. end_info = png_create_info_struct(png_ptr);
  306. if (!end_info)
  307. goto cleanup;
  308. png_init_io(png_ptr, fp);
  309. png_set_sig_bytes(png_ptr, number);
  310. // Read PNG information
  311. png_read_info(png_ptr, info_ptr);
  312. // Get count of bytes per row
  313. rowbytes = png_get_rowbytes(png_ptr, info_ptr);
  314. row = new png_byte[rowbytes];
  315. width = png_get_image_width(png_ptr, info_ptr);
  316. height = png_get_image_height(png_ptr, info_ptr);
  317. if(info_ptr->channels==3)
  318. {
  319. png_set_strip_16(png_ptr);
  320. png_set_packing(png_ptr);
  321. png_set_bgr(png_ptr);
  322. }
  323. hDC = GetDC(NULL);
  324. {
  325. CAutoLock lock(&m_csLock);
  326. if(m_bLoadCancelled)
  327. goto cleanup;
  328. m_hBitmap = CreateCompatibleBitmap(hDC, width, height);
  329. }
  330. pBMI = (BITMAPINFO*)new BYTE[sizeof(BITMAPINFO)+256*4];
  331. memset(pBMI, 0, sizeof(BITMAPINFO)+256*4);
  332. pBMI->bmiHeader.biSize = sizeof(BITMAPINFO);
  333. pBMI->bmiHeader.biBitCount = 8*info_ptr->channels;
  334. pBMI->bmiHeader.biWidth = width;
  335. pBMI->bmiHeader.biHeight = height;
  336. pBMI->bmiHeader.biPlanes = 1;
  337. pBMI->bmiHeader.biCompression = BI_RGB;
  338. pBMI->bmiHeader.biSizeImage = rowbytes*height;
  339. if( info_ptr->channels == 1 )
  340. {
  341. RGBQUAD* palette = pBMI->bmiColors;
  342. int i;
  343. for( i = 0; i < 256; i++ )
  344. {
  345. palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i;
  346. palette[i].rgbReserved = 0;
  347. }
  348. palette[256].rgbBlue = palette[256].rgbGreen = palette[256].rgbRed = 255;
  349. }
  350. for(y=height-1; y>=0; y--)
  351. {
  352. png_read_rows(png_ptr, &row, png_bytepp_NULL, 1);
  353. {
  354. CAutoLock lock(&m_csLock);
  355. int n = SetDIBits(hDC, m_hBitmap, y, 1, row, pBMI, DIB_RGB_COLORS);
  356. if(n==0)
  357. goto cleanup;
  358. }
  359. }
  360. /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */
  361. png_read_end(png_ptr, info_ptr);
  362. bStatus = TRUE;
  363. cleanup:
  364. if(fp!=NULL)
  365. {
  366. fclose(fp);
  367. }
  368. if(png_ptr)
  369. {
  370. png_destroy_read_struct(&png_ptr,
  371. (png_infopp)&info_ptr, (png_infopp)&end_info);
  372. }
  373. if(row)
  374. {
  375. delete [] row;
  376. }
  377. if(pBMI)
  378. {
  379. delete [] pBMI;
  380. }
  381. if(!bStatus)
  382. {
  383. Destroy();
  384. }
  385. return bStatus;
  386. }
  387. BOOL CImage::LoadBitmapFromJPEGFile(LPTSTR szFileName)
  388. {
  389. BOOL bStatus = false;
  390. struct jpeg_decompress_struct cinfo;
  391. struct jpeg_error_mgr jerr;
  392. FILE* fp = NULL;
  393. JSAMPROW row = NULL;
  394. BITMAPINFO bmi;
  395. HDC hDC = NULL;
  396. cinfo.err = jpeg_std_error(&jerr);
  397. jpeg_create_decompress(&cinfo);
  398. _TFOPEN_S(fp, szFileName, _T("rb"));
  399. if (!fp)
  400. {
  401. goto cleanup;
  402. }
  403. jpeg_stdio_src(&cinfo, fp);
  404. jpeg_read_header(&cinfo, TRUE);
  405. jpeg_start_decompress(&cinfo);
  406. row = new BYTE[cinfo.output_width*3+10];
  407. hDC = GetDC(NULL);
  408. {
  409. CAutoLock lock(&m_csLock);
  410. if(m_bLoadCancelled)
  411. goto cleanup;
  412. m_hBitmap = CreateCompatibleBitmap(hDC, cinfo.output_width, cinfo.output_height);
  413. }
  414. memset(&bmi, 0, sizeof(bmi));
  415. bmi.bmiHeader.biSize = sizeof(bmi);
  416. bmi.bmiHeader.biBitCount = 24;
  417. bmi.bmiHeader.biWidth = cinfo.output_width;
  418. bmi.bmiHeader.biHeight = cinfo.output_height;
  419. bmi.bmiHeader.biPlanes = 1;
  420. bmi.bmiHeader.biCompression = BI_RGB;
  421. bmi.bmiHeader.biSizeImage = cinfo.output_width*cinfo.output_height*3;
  422. while (cinfo.output_scanline < cinfo.output_height)
  423. {
  424. jpeg_read_scanlines(&cinfo, &row, 1);
  425. if(cinfo.out_color_components==3)
  426. {
  427. // Convert RGB to BGR
  428. UINT i;
  429. for(i=0; i<cinfo.output_width; i++)
  430. {
  431. BYTE tmp = row[i*3+0];
  432. row[i*3+0] = row[i*3+2];
  433. row[i*3+2] = tmp;
  434. }
  435. }
  436. else
  437. {
  438. // Convert grayscale to BGR
  439. int i;
  440. for(i=cinfo.output_width-1; i>=0; i--)
  441. {
  442. row[i*3+0] = row[i];
  443. row[i*3+1] = row[i];
  444. row[i*3+2] = row[i];
  445. }
  446. }
  447. {
  448. CAutoLock lock(&m_csLock);
  449. int n = SetDIBits(hDC, m_hBitmap, cinfo.output_height-cinfo.output_scanline, 1, row, &bmi, DIB_RGB_COLORS);
  450. if(n==0)
  451. goto cleanup;
  452. }
  453. }
  454. jpeg_finish_decompress(&cinfo);
  455. jpeg_destroy_decompress(&cinfo);
  456. bStatus = true;
  457. cleanup:
  458. if(row)
  459. delete [] row;
  460. if(!bStatus)
  461. {
  462. Destroy();
  463. }
  464. if(fp!=NULL)
  465. {
  466. fclose(fp);
  467. fp = NULL;
  468. }
  469. return bStatus;
  470. }
  471. void CImage::Draw(HDC hDC, LPRECT prcDraw)
  472. {
  473. CAutoLock lock(&m_csLock);
  474. HPALETTE hOldPalette = NULL;
  475. CRect rcDraw = prcDraw;
  476. BITMAP bm;
  477. GetObject( m_hBitmap, sizeof(BITMAP), &bm );
  478. HDC hMemDC = CreateCompatibleDC( hDC );
  479. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, m_hBitmap );
  480. if(m_hPalette)
  481. {
  482. hOldPalette = SelectPalette(hDC, m_hPalette, FALSE );
  483. RealizePalette( hDC );
  484. }
  485. if((float)rcDraw.Width()/(float)bm.bmWidth <
  486. (float)rcDraw.Height()/(float)bm.bmHeight)
  487. {
  488. int nDstMid = rcDraw.top + rcDraw.Height()/2;
  489. int nDstHeight = (int)( rcDraw.Width()*(float)bm.bmHeight/bm.bmWidth );
  490. rcDraw.top = nDstMid - nDstHeight/2;
  491. rcDraw.bottom = nDstMid + nDstHeight/2;
  492. }
  493. else
  494. {
  495. int nDstMid = rcDraw.left + rcDraw.Width()/2;
  496. int nDstWidth = (int)( rcDraw.Height()*(float)bm.bmWidth/bm.bmHeight );
  497. rcDraw.left = nDstMid - nDstWidth/2;
  498. rcDraw.right = nDstMid + nDstWidth/2;
  499. }
  500. int nOldMode = SetStretchBltMode(hDC, HALFTONE);
  501. StretchBlt(hDC, rcDraw.left, rcDraw.top, rcDraw.Width(), rcDraw.Height(),
  502. hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
  503. SetStretchBltMode(hDC, nOldMode);
  504. SelectObject( hMemDC, hOldBitmap );
  505. if(m_hPalette)
  506. {
  507. SelectPalette( hDC, hOldPalette, FALSE );
  508. }
  509. }
  510. //-----------------------------------------------------------------------------
  511. // CVideo implementation
  512. //-----------------------------------------------------------------------------
  513. CVideo::CVideo()
  514. {
  515. m_pf = NULL;
  516. m_hbmpFrame = NULL;
  517. m_pFrameBits = NULL;
  518. m_pDIB = NULL;
  519. m_hDC = NULL;
  520. m_hOldBitmap = NULL;
  521. m_buf = NULL;
  522. m_psetup = NULL;
  523. m_pctx = NULL;
  524. m_pos = 0;
  525. m_nFrameWidth = 0;
  526. m_nFrameHeight = 0;
  527. m_nFrameInterval = 0;
  528. ogg_sync_init(&m_state);
  529. ogg_stream_init(&m_stream, 0);
  530. memset(&m_packet, 0, sizeof(m_packet));
  531. th_info_init(&m_info);
  532. th_comment_init(&m_comment);
  533. }
  534. CVideo::~CVideo()
  535. {
  536. Destroy();
  537. }
  538. BOOL CVideo::IsVideoFile(LPCTSTR szFileName)
  539. {
  540. FILE* f = NULL;
  541. _TFOPEN_S(f, szFileName, _T("rb"));
  542. if(f==NULL)
  543. return FALSE;
  544. if(IsOGG(f))
  545. {
  546. fclose(f);
  547. return TRUE;
  548. }
  549. fclose(f);
  550. return FALSE;
  551. }
  552. BOOL CVideo::IsOGG(FILE* f)
  553. {
  554. rewind(f);
  555. // Read first three bytes (Ogg).
  556. BYTE uchBytes[4];
  557. int n = (int)fread(uchBytes, 1, 3, f);
  558. if(n!=3)
  559. return FALSE;
  560. if(memcmp(uchBytes, "Ogg", 3)==0)
  561. return TRUE; // This is an OGG file
  562. return FALSE;
  563. }
  564. // Loads video from file.
  565. BOOL CVideo::Load(LPCTSTR szFileName)
  566. {
  567. // Destroy if previously loaded
  568. if(!m_sFileName.IsEmpty())
  569. Destroy();
  570. // Open file
  571. FILE* f = NULL;
  572. _TFOPEN_S(f, szFileName, _T("rb"));
  573. if(f==NULL)
  574. return FALSE;
  575. // Check OGG signature
  576. if(IsOGG(f))
  577. {
  578. fclose(f);
  579. // Load OGG video
  580. return LoadOggFile(szFileName);
  581. }
  582. // Close file
  583. fclose(f);
  584. return FALSE;
  585. }
  586. void CVideo::Destroy()
  587. {
  588. m_sFileName.Empty();
  589. if(m_pf)
  590. {
  591. fclose(m_pf);
  592. m_pf = NULL;
  593. }
  594. //ogg_packet_clear(&m_packet);
  595. ogg_stream_clear(&m_stream);
  596. // Call th_decode_free() to release all decoder memory.
  597. if(m_pctx)
  598. {
  599. th_decode_free(m_pctx);
  600. m_pctx = NULL;
  601. }
  602. ogg_sync_clear(&m_state);
  603. th_info_clear(&m_info);
  604. th_comment_clear(&m_comment);
  605. if(m_hbmpFrame!=NULL)
  606. {
  607. DeleteObject(m_hbmpFrame);
  608. m_hbmpFrame = NULL;
  609. }
  610. if(m_pDIB)
  611. {
  612. delete [] m_pDIB;
  613. m_pDIB = NULL;
  614. }
  615. m_pFrameBits = NULL;
  616. if(m_hDC!=NULL)
  617. {
  618. DeleteDC(m_hDC);
  619. m_hDC = NULL;
  620. }
  621. m_hOldBitmap = NULL;
  622. }
  623. BOOL CVideo::LoadOggFile(LPCTSTR szFileName)
  624. {
  625. bool bStatus = false;
  626. int ret = -1;
  627. // Open OGG file
  628. _TFOPEN_S(m_pf, szFileName, _T("rb"));
  629. if(m_pf==NULL)
  630. goto cleanup; // Error opening file
  631. // Init theora decoder structures
  632. th_info_init(&m_info);
  633. th_comment_init(&m_comment);
  634. // The first thing we need to do when reading an Ogg file is find
  635. // the first page of data. We use a ogg_sync_state structure to keep
  636. // track of search for the page data. This needs to be initialized
  637. // with ogg_sync_init and later cleaned up with ogg_sync_clear:
  638. if(0!=ogg_sync_init(&m_state))
  639. goto cleanup; // Error initializing sync state
  640. // Parse the header packets by repeatedly calling th_decode_headerin()
  641. while(ReadOGGPacket())
  642. {
  643. ret = th_decode_headerin(&m_info, &m_comment, &m_psetup, &m_packet);
  644. if(ret==0)
  645. {
  646. // Video data encountered
  647. break;
  648. }
  649. else if(ret==TH_EFAULT)
  650. {
  651. // Some parameters are incorrect
  652. goto cleanup;
  653. }
  654. else if(ret==TH_EBADHEADER)
  655. {
  656. //goto cleanup;
  657. }
  658. else if(ret==TH_EVERSION)
  659. {
  660. //goto cleanup;
  661. }
  662. else if(ret==TH_ENOTFORMAT )
  663. {
  664. //goto cleanup;
  665. }
  666. }
  667. /*Allocate YV12 image */
  668. m_nFrameWidth = m_info.frame_width;
  669. m_nFrameHeight = m_info.frame_height;
  670. m_nFrameInterval = (int)((float)m_info.fps_denominator/(float)m_info.fps_numerator*1000);
  671. if(m_hbmpFrame==NULL)
  672. {
  673. // Calculate frame size
  674. CreateFrameDIB(m_nFrameWidth, m_nFrameHeight, 24);
  675. }
  676. // Allocate a th_dec_ctx handle with th_decode_alloc().
  677. m_pctx = th_decode_alloc(&m_info, m_psetup);
  678. // Call th_setup_free() to free any memory used for codec setup information.
  679. th_setup_free(m_psetup);
  680. m_psetup = NULL;
  681. // Perform any additional decoder configuration with th_decode_ctl().
  682. m_sFileName = szFileName;
  683. // Done
  684. bStatus = true;
  685. cleanup:
  686. return bStatus;
  687. }
  688. BOOL CVideo::ReadOGGPage()
  689. {
  690. BOOL bStatus = FALSE;
  691. size_t nBytes = 0;
  692. // Read an entire page from OGG file
  693. while(ogg_sync_pageout(&m_state, &m_page) != 1)
  694. {
  695. // Allocate buffer
  696. m_buf = ogg_sync_buffer(&m_state, 4096);
  697. if(m_buf==NULL)
  698. goto cleanup;
  699. // Read a portion of data from file
  700. nBytes = fread(m_buf, 1, 4096, m_pf);
  701. if(nBytes==0)
  702. goto cleanup; // End of file
  703. if(0!=ogg_sync_wrote(&m_state, (long)nBytes))
  704. goto cleanup; // Failed
  705. }
  706. bStatus = true;
  707. cleanup:
  708. return bStatus;
  709. }
  710. BOOL CVideo::ReadOGGPacket()
  711. {
  712. BOOL bStatus = FALSE;
  713. int ret = -1;
  714. while(1)
  715. {
  716. // Call ogg_stream_packetout. This will return a value indicating if
  717. // a packet of data is available in the stream. If it is not then we
  718. // need to read another page (following the same steps previously) and
  719. // add it to the stream, calling ogg_stream_packetout again until it
  720. // tells us a packet is available. The packet&#x2019;s data is stored in an
  721. // ogg_packet object.
  722. ret = ogg_stream_packetout(&m_stream, &m_packet);
  723. if (ret == 0)
  724. {
  725. // Need more data to be able to complete the packet
  726. // New page
  727. if(!ReadOGGPage())
  728. goto cleanup;
  729. // If this page is the beginning of the logical stream...
  730. if (ogg_page_bos(&m_page))
  731. {
  732. // Get page's serial number
  733. int serial = ogg_page_serialno(&m_page);
  734. // Init OGG stream
  735. ret = ogg_stream_init(&m_stream, serial);
  736. if(ret != 0)
  737. goto cleanup; // Failed to init stream
  738. }
  739. // Pass the page data to stream
  740. ret = ogg_stream_pagein(&m_stream, &m_page);
  741. if(ret!=0)
  742. goto cleanup;
  743. continue;
  744. }
  745. else if (ret == -1)
  746. {
  747. // We are out of sync and there is a gap in the data.
  748. // We lost a page somewhere.
  749. break;
  750. }
  751. // A packet is available, this is what we pass to the
  752. // theora library to decode.
  753. bStatus = true;
  754. break;
  755. }
  756. cleanup:
  757. return bStatus;
  758. }
  759. // Decodes next video frame and returns pointer to bitmap.
  760. HBITMAP CVideo::DecodeFrame(BOOL bFirstFrame, CSize& FrameSize, int& nDuration)
  761. {
  762. FrameSize.cx = m_nFrameWidth;
  763. FrameSize.cy = m_nFrameHeight;
  764. nDuration = m_nFrameInterval;
  765. // For the first frame, we use the packet that was read previously
  766. // For next frames, we need to read new packets
  767. if(!bFirstFrame)
  768. {
  769. // Read packet
  770. if(!ReadOGGPacket())
  771. return NULL; // No more packets
  772. }
  773. // Feed the packet to decoder
  774. int ret = th_decode_packetin(m_pctx, &m_packet, &m_pos);
  775. if(ret!=0 && ret!=TH_DUPFRAME)
  776. return NULL; // Decoding error
  777. if(ret!=TH_DUPFRAME)
  778. {
  779. // Retrieve the uncompressed video data via th_decode_ycbcr_out().
  780. th_decode_ycbcr_out(m_pctx, &m_raw[0]);
  781. CAutoLock lock(&m_csLock);
  782. // Convert YV12 to RGB
  783. YV12_To_RGB((unsigned char*)m_pFrameBits,
  784. m_nFrameWidth, m_nFrameHeight,
  785. m_nFrameWidth*3+(m_nFrameWidth*3)%4,
  786. &m_raw[0]);
  787. }
  788. // Return bitmap
  789. return m_hbmpFrame;
  790. }
  791. void CVideo::DrawFrame(HDC hDC, LPRECT prcDraw)
  792. {
  793. CAutoLock lock(&m_csLock);
  794. CRect rcDraw = prcDraw;
  795. BITMAP bm;
  796. GetObject(m_hbmpFrame, sizeof(BITMAP), &bm );
  797. if((float)rcDraw.Width()/(float)bm.bmWidth <
  798. (float)rcDraw.Height()/(float)bm.bmHeight)
  799. {
  800. int nDstMid = rcDraw.top + rcDraw.Height()/2;
  801. int nDstHeight = (int)( rcDraw.Width()*(float)bm.bmHeight/bm.bmWidth );
  802. rcDraw.top = nDstMid - nDstHeight/2;
  803. rcDraw.bottom = nDstMid + nDstHeight/2;
  804. }
  805. else
  806. {
  807. int nDstMid = rcDraw.left + rcDraw.Width()/2;
  808. int nDstWidth = (int)( rcDraw.Height()*(float)bm.bmWidth/bm.bmHeight );
  809. rcDraw.left = nDstMid - nDstWidth/2;
  810. rcDraw.right = nDstMid + nDstWidth/2;
  811. }
  812. int nOldMode = SetStretchBltMode(hDC, HALFTONE);
  813. StretchBlt(hDC, rcDraw.left, rcDraw.top, rcDraw.Width(), rcDraw.Height(),
  814. m_hDC, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY );
  815. SetStretchBltMode(hDC, nOldMode);
  816. }
  817. void CVideo::Reset()
  818. {
  819. }
  820. // Returns TRUE if video is valid, otherwise returns FALSE
  821. BOOL CVideo::IsValid()
  822. {
  823. return m_sFileName.IsEmpty()?FALSE:TRUE;
  824. }
  825. // Converts an YV12 image to RGB24 image.
  826. void CVideo::YV12_To_RGB(unsigned char *pRGBData, int nFrameWidth,
  827. int nFrameHeight, int nRGBStride, th_ycbcr_buffer raw)
  828. {
  829. int x, y;
  830. for(y=0; y<nFrameHeight;y++)
  831. {
  832. for (x=0; x < nFrameWidth; x ++)
  833. {
  834. int nRGBOffs = y*nRGBStride+x*3;
  835. float Y = raw[0].data[y*raw[0].stride+x];
  836. float U = raw[1].data[y/2*raw[1].stride+x/2];
  837. float V = raw[2].data[y/2*raw[2].stride+x/2];
  838. pRGBData[nRGBOffs+0] = CLAMP((int)(1.164*(Y - 16) + 2.018*(U - 128)));
  839. pRGBData[nRGBOffs+1] = CLAMP((int)(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128)));
  840. pRGBData[nRGBOffs+2] = CLAMP((int)(1.164*(Y - 16) + 1.596*(V - 128)));
  841. }
  842. }
  843. }
  844. BOOL CVideo::CreateFrameDIB(DWORD dwWidth, DWORD dwHeight, int nBits)
  845. {
  846. if (m_pDIB)
  847. return FALSE;
  848. const DWORD dwcBihSize = sizeof(BITMAPINFOHEADER);
  849. // Calculate the memory required for the DIB
  850. DWORD dwSize = dwcBihSize +
  851. (2>>nBits) * sizeof(RGBQUAD) +
  852. ((nBits * dwWidth) * dwHeight);
  853. m_pDIB = (LPBITMAPINFO)new BYTE[dwSize];
  854. if (!m_pDIB)
  855. return FALSE;
  856. m_pDIB->bmiHeader.biSize = dwcBihSize;
  857. m_pDIB->bmiHeader.biWidth = dwWidth;
  858. m_pDIB->bmiHeader.biHeight = -(LONG)dwHeight;
  859. m_pDIB->bmiHeader.biBitCount = (WORD)nBits;
  860. m_pDIB->bmiHeader.biPlanes = 1;
  861. m_pDIB->bmiHeader.biCompression = BI_RGB;
  862. m_pDIB->bmiHeader.biXPelsPerMeter = 1000;
  863. m_pDIB->bmiHeader.biYPelsPerMeter = 1000;
  864. m_pDIB->bmiHeader.biClrUsed = 0;
  865. m_pDIB->bmiHeader.biClrImportant = 0;
  866. LPRGBQUAD lpColors =
  867. (LPRGBQUAD)(m_pDIB+m_pDIB->bmiHeader.biSize);
  868. int nColors=2>>m_pDIB->bmiHeader.biBitCount;
  869. for(int i=0;i<nColors;i++)
  870. {
  871. lpColors[i].rgbRed=0;
  872. lpColors[i].rgbBlue=0;
  873. lpColors[i].rgbGreen=0;
  874. lpColors[i].rgbReserved=0;
  875. }
  876. m_hDC = CreateCompatibleDC(GetDC(NULL));
  877. m_hbmpFrame = CreateDIBSection(m_hDC, m_pDIB, DIB_RGB_COLORS, &m_pFrameBits,
  878. NULL, 0);
  879. m_hOldBitmap = (HBITMAP)SelectObject(m_hDC, m_hbmpFrame);
  880. return TRUE;
  881. }
  882. //-----------------------------------------------------------------------------
  883. // CFilePreviewCtrl implementation
  884. //-----------------------------------------------------------------------------
  885. CFilePreviewCtrl::CFilePreviewCtrl()
  886. {
  887. m_xChar = 10;
  888. m_yChar = 10;
  889. m_nHScrollPos = 0;
  890. m_nHScrollMax = 0;
  891. m_nMaxColsPerPage = 0;
  892. m_nMaxLinesPerPage = 0;
  893. m_nMaxDisplayWidth = 0;
  894. m_uNumLines = 0;
  895. m_nVScrollPos = 0;
  896. m_nVScrollMax = 0;
  897. m_nBytesPerLine = 16;
  898. m_cchTabLength = 4;
  899. m_sEmptyMsg = _T("No data to display");
  900. m_hFont = CreateFont(14, 7, 0, 0, 0, 0, 0, 0, ANSI_CHARSET, 0, 0,
  901. ANTIALIASED_QUALITY, FIXED_PITCH, _T("Courier"));
  902. m_hWorkerThread = NULL;
  903. m_bCancelled = FALSE;
  904. m_PreviewMode = PREVIEW_HEX;
  905. m_TextEncoding = ENC_ASCII;
  906. m_nEncSignatureLen = 0;
  907. }
  908. CFilePreviewCtrl::~CFilePreviewCtrl()
  909. {
  910. m_bmp.Destroy();
  911. m_fm.Destroy();
  912. DeleteObject(m_hFont);
  913. }
  914. LPCTSTR CFilePreviewCtrl::GetFile()
  915. {
  916. if(m_sFileName.IsEmpty())
  917. return NULL;
  918. return m_sFileName;
  919. }
  920. BOOL CFilePreviewCtrl::SetFile(LPCTSTR szFileName, PreviewMode mode, TextEncoding enc)
  921. {
  922. // If we are currently processing some file in background,
  923. // stop the worker thread
  924. if(m_hWorkerThread!=NULL)
  925. {
  926. m_bCancelled = TRUE;
  927. m_bmp.Cancel();
  928. WaitForSingleObject(m_hWorkerThread, INFINITE);
  929. m_hWorkerThread = NULL;
  930. }
  931. CAutoLock lock(&m_csLock);
  932. m_sFileName = szFileName;
  933. if(mode==PREVIEW_AUTO)
  934. m_PreviewMode = DetectPreviewMode(m_sFileName);
  935. else
  936. m_PreviewMode = mode;
  937. if(szFileName==NULL)
  938. {
  939. m_fm.Destroy();
  940. }
  941. else
  942. {
  943. if(!m_fm.Init(m_sFileName))
  944. {
  945. m_sFileName.Empty();
  946. return FALSE;
  947. }
  948. }
  949. CRect rcClient;
  950. GetClientRect(&rcClient);
  951. HDC hDC = GetDC();
  952. HFONT hOldFont = (HFONT)SelectObject(hDC, m_hFont);
  953. LOGFONT lf;
  954. ZeroMemory(&lf, sizeof(LOGFONT));
  955. GetObject(m_hFont, sizeof(LOGFONT), &lf);
  956. m_xChar = lf.lfWidth;
  957. m_yChar = lf.lfHeight;
  958. SelectObject(hDC, hOldFont);
  959. m_nVScrollPos = 0;
  960. m_nVScrollMax = 0;
  961. m_nHScrollPos = 0;
  962. m_nHScrollMax = 0;
  963. m_aTextLines.clear();
  964. m_uNumLines = 0;
  965. m_nMaxDisplayWidth = 0;
  966. m_bmp.Destroy();
  967. m_video.Destroy();
  968. if(m_PreviewMode==PREVIEW_HEX)
  969. {
  970. if(m_fm.GetSize()!=0)
  971. {
  972. m_nMaxDisplayWidth =
  973. 8 + //adress
  974. 2 + //padding
  975. m_nBytesPerLine * 3 + //hex column
  976. 1 + //padding
  977. m_nBytesPerLine; //ascii column
  978. }
  979. m_uNumLines = m_fm.GetSize() / m_nBytesPerLine;
  980. if(m_fm.GetSize() % m_nBytesPerLine)
  981. m_uNumLines++;
  982. }
  983. else if(m_PreviewMode==PREVIEW_TEXT)
  984. {
  985. if(enc==ENC_AUTO)
  986. m_TextEncoding = DetectTextEncoding(m_sFileName, m_nEncSignatureLen);
  987. else
  988. {
  989. m_TextEncoding = enc;
  990. // Determine the length of the signature.
  991. int nSignatureLen = 0;
  992. TextEncoding enc2 = DetectTextEncoding(m_sFileName, nSignatureLen);
  993. if(enc==enc2)
  994. m_nEncSignatureLen = nSignatureLen;
  995. }
  996. m_bCancelled = FALSE;
  997. m_hWorkerThread = CreateThread(NULL, 0, WorkerThread, this, 0, NULL);
  998. ::SetTimer(m_hWnd, 0, 250, NULL);
  999. }
  1000. else if(m_PreviewMode==PREVIEW_IMAGE)
  1001. {
  1002. m_bCancelled = FALSE;
  1003. m_hWorkerThread = CreateThread(NULL, 0, WorkerThread, this, 0, NULL);
  1004. ::SetTimer(m_hWnd, 0, 250, NULL);
  1005. }
  1006. else if(m_PreviewMode==PREVIEW_VIDEO)
  1007. {
  1008. m_bCancelled = FALSE;
  1009. m_hWorkerThread = CreateThread(NULL, 0, WorkerThread, this, 0, NULL);
  1010. //::SetTimer(m_hWnd, 0, 250, NULL);
  1011. }
  1012. SetupScrollbars();
  1013. InvalidateRect(NULL, FALSE);
  1014. UpdateWindow();
  1015. return TRUE;
  1016. }
  1017. PreviewMode CFilePreviewCtrl::GetPreviewMode()
  1018. {
  1019. return m_PreviewMode;
  1020. }
  1021. void CFilePreviewCtrl::SetPreviewMode(PreviewMode mode)
  1022. {
  1023. SetFile(m_sFileName, mode);
  1024. }
  1025. TextEncoding CFilePreviewCtrl::GetTextEncoding()
  1026. {
  1027. return m_TextEncoding;
  1028. }
  1029. void CFilePreviewCtrl::SetTextEncoding(TextEncoding enc)
  1030. {
  1031. SetFile(m_sFileName, m_PreviewMode, enc);
  1032. }
  1033. PreviewMode CFilePreviewCtrl::DetectPreviewMode(LPCTSTR szFileName)
  1034. {
  1035. PreviewMode mode = PREVIEW_HEX;
  1036. CString sFileName;
  1037. std::set<CString>::iterator it;
  1038. std::set<CString> aTextFileExtensions;
  1039. CString sExtension;
  1040. sFileName = szFileName;
  1041. if(CImage::IsImageFile(sFileName))
  1042. {
  1043. mode = PREVIEW_IMAGE;
  1044. goto cleanup;
  1045. }
  1046. else if(CVideo::IsVideoFile(sFileName))
  1047. {
  1048. mode = PREVIEW_VIDEO;
  1049. goto cleanup;
  1050. }
  1051. int backslash_pos = sFileName.ReverseFind('\\');
  1052. if(backslash_pos>=0)
  1053. sFileName = sFileName.Mid(backslash_pos+1);
  1054. int dot_pos = sFileName.ReverseFind('.');
  1055. if(dot_pos>0)
  1056. sExtension = sFileName.Mid(dot_pos+1);
  1057. sExtension.MakeUpper();
  1058. aTextFileExtensions.insert(_T("TXT"));
  1059. aTextFileExtensions.insert(_T("INI"));
  1060. aTextFileExtensions.insert(_T("LOG"));
  1061. aTextFileExtensions.insert(_T("XML"));
  1062. aTextFileExtensions.insert(_T("HTM"));
  1063. aTextFileExtensions.insert(_T("HTML"));
  1064. aTextFileExtensions.insert(_T("JS"));
  1065. aTextFileExtensions.insert(_T("C"));
  1066. aTextFileExtensions.insert(_T("H"));
  1067. aTextFileExtensions.insert(_T("CPP"));
  1068. aTextFileExtensions.insert(_T("HPP"));
  1069. it = aTextFileExtensions.find(sExtension);
  1070. if(it!=aTextFileExtensions.end())
  1071. {
  1072. mode = PREVIEW_TEXT;
  1073. }
  1074. cleanup:
  1075. return mode;
  1076. }
  1077. TextEncoding CFilePreviewCtrl::DetectTextEncoding(LPCTSTR szFileName, int& nSignatureLen)
  1078. {
  1079. TextEncoding enc = ENC_ASCII;
  1080. nSignatureLen = 0;
  1081. FILE* f = NULL;
  1082. #if _MSC_VER<1400
  1083. f = _tfopen(szFileName, _T("rb"));
  1084. #else
  1085. _tfopen_s(&f, szFileName, _T("rb"));
  1086. #endif
  1087. if(f==NULL)
  1088. goto cleanup;
  1089. BYTE signature2[2];
  1090. size_t nRead = fread(signature2, 1, 2, f);
  1091. if(nRead!=2)
  1092. goto cleanup;
  1093. // Compare with UTF-16 LE signature
  1094. if(signature2[0]==0xFF &&
  1095. signature2[1]==0xFE
  1096. )
  1097. {
  1098. enc = ENC_UTF16_LE;
  1099. nSignatureLen = 2;
  1100. goto cleanup;
  1101. }
  1102. // Compare with UTF-16 BE signature
  1103. if(signature2[0]==0xFE &&
  1104. signature2[1]==0xFF
  1105. )
  1106. {
  1107. enc = ENC_UTF16_BE;
  1108. nSignatureLen = 2;
  1109. goto cleanup;
  1110. }
  1111. rewind(f);
  1112. BYTE signature3[3];
  1113. nRead = fread(signature3, 1, 3, f);
  1114. if(nRead!=3)
  1115. goto cleanup;
  1116. // Compare with UTF-8 signature
  1117. if(signature3[0]==0xEF &&
  1118. signature3[1]==0xBB &&
  1119. signature3[2]==0xBF
  1120. )
  1121. {
  1122. enc = ENC_UTF8;
  1123. nSignatureLen = 3;
  1124. goto cleanup;
  1125. }
  1126. cleanup:
  1127. fclose(f);
  1128. return enc;
  1129. }
  1130. DWORD WINAPI CFilePreviewCtrl::WorkerThread(LPVOID lpParam)
  1131. {
  1132. CFilePreviewCtrl* pCtrl = (CFilePreviewCtrl*)lpParam;
  1133. pCtrl->DoInWorkerThread();
  1134. return 0;
  1135. }
  1136. void CFilePreviewCtrl::DoInWorkerThread()
  1137. {
  1138. if(m_PreviewMode==PREVIEW_TEXT)
  1139. ParseText();
  1140. else if(m_PreviewMode==PREVIEW_IMAGE)
  1141. LoadBitmap();
  1142. if(m_PreviewMode==PREVIEW_VIDEO)
  1143. LoadVideo();
  1144. }
  1145. WCHAR swap_bytes(WCHAR src_char)
  1146. {
  1147. return (WCHAR)MAKEWORD((src_char>>8), (src_char&0xFF));
  1148. }
  1149. void CFilePreviewCtrl::ParseText()
  1150. {
  1151. DWORD dwFileSize = (DWORD)m_fm.GetSize();
  1152. DWORD dwOffset = 0;
  1153. DWORD dwPrevOffset = 0;
  1154. int nTabs = 0;
  1155. if(dwFileSize!=0)
  1156. {
  1157. CAutoLock lock(&m_csLock);
  1158. if(m_PreviewMode==PREVIEW_TEXT)
  1159. {
  1160. dwOffset+=m_nEncSignatureLen;
  1161. m_aTextLines.push_back(dwOffset);
  1162. }
  1163. else
  1164. {
  1165. m_aTextLines.push_back(0);
  1166. }
  1167. m_uNumLines++;
  1168. }
  1169. for(;;)
  1170. {
  1171. {
  1172. CAutoLock lock(&m_csLock);
  1173. if(m_bCancelled)
  1174. break;
  1175. }
  1176. DWORD dwLength = 4096;
  1177. if(dwOffset+dwLength>=dwFileSize)
  1178. dwLength = dwFileSize-dwOffset;
  1179. if(dwLength==0)
  1180. break;
  1181. LPBYTE ptr = m_fm.CreateView(dwOffset, dwLength);
  1182. UINT i;
  1183. for(i=0; i<dwLength; )
  1184. {
  1185. {
  1186. CAutoLock lock(&m_csLock);
  1187. if(m_bCancelled)
  1188. break;
  1189. }
  1190. if(m_TextEncoding==ENC_UTF16_LE || m_TextEncoding==ENC_UTF16_BE)
  1191. {
  1192. WCHAR src_char = ((WCHAR*)ptr)[i/2];
  1193. WCHAR c = m_TextEncoding==ENC_UTF16_LE?src_char:swap_bytes(src_char);
  1194. if(c=='\t')
  1195. {
  1196. nTabs++;
  1197. }
  1198. else if(c=='\n')
  1199. {
  1200. CAutoLock lock(&m_csLock);
  1201. m_aTextLines.push_back(dwOffset+i+2);
  1202. int cchLineLength = dwOffset+i+2-dwPrevOffset;
  1203. if(nTabs!=0)
  1204. cchLineLength += nTabs*(m_cchTabLength-1);
  1205. m_nMaxDisplayWidth = max(m_nMaxDisplayWidth, cchLineLength);
  1206. m_uNumLines++;
  1207. dwPrevOffset = dwOffset+i+2;
  1208. nTabs = 0;
  1209. }
  1210. i+=2;
  1211. }
  1212. else
  1213. {
  1214. char c = ((char*)ptr)[i];
  1215. if(c=='\t')
  1216. {
  1217. nTabs++;
  1218. }
  1219. else if(c=='\n')
  1220. {
  1221. CAutoLock lock(&m_csLock);
  1222. m_aTextLines.push_back(dwOffset+i+1);
  1223. int cchLineLength = dwOffset+i+1-dwPrevOffset;
  1224. if(nTabs!=0)
  1225. cchLineLength += nTabs*(m_cchTabLength-1);
  1226. m_nMaxDisplayWidth = max(m_nMaxDisplayWidth, cchLineLength);
  1227. m_uNumLines++;
  1228. dwPrevOffset = dwOffset+i+1;
  1229. nTabs = 0;
  1230. }
  1231. i++;
  1232. }
  1233. }
  1234. dwOffset += dwLength;
  1235. }
  1236. PostMessage(WM_FPC_COMPLETE);
  1237. }
  1238. void CFilePreviewCtrl::LoadBitmap()
  1239. {
  1240. m_bmp.Load(m_sFileName);
  1241. PostMessage(WM_FPC_COMPLETE);
  1242. }
  1243. void CFilePreviewCtrl::LoadVideo()
  1244. {
  1245. int nFrame = 0;
  1246. CSize FrameSize;
  1247. int nFrameInterval;
  1248. if(m_video.Load(m_sFileName))
  1249. {
  1250. while(m_video.DecodeFrame(nFrame==0?TRUE:FALSE, FrameSize, nFrameInterval))
  1251. {
  1252. if(m_bCancelled)
  1253. break;
  1254. nFrame++;
  1255. InvalidateRect(NULL);
  1256. Sleep(nFrameInterval);
  1257. }
  1258. }
  1259. PostMessage(WM_FPC_COMPLETE);
  1260. }
  1261. void CFilePreviewCtrl::SetEmptyMessage(CString sText)
  1262. {
  1263. m_sEmptyMsg = sText;
  1264. }
  1265. BOOL CFilePreviewCtrl::SetBytesPerLine(int nBytesPerLine)
  1266. {
  1267. if(nBytesPerLine<0)
  1268. return FALSE;
  1269. m_nBytesPerLine = nBytesPerLine;
  1270. return TRUE;
  1271. }
  1272. void CFilePreviewCtrl::SetupScrollbars()
  1273. {
  1274. CAutoLock lock(&m_csLock);
  1275. CRect rcClient;
  1276. GetClientRect(&rcClient);
  1277. SCROLLINFO sInfo;
  1278. // Vertical scrollbar
  1279. m_nMaxLinesPerPage = (int)min(m_uNumLines, rcClient.Height() / m_yChar);
  1280. m_nVScrollMax = (int)max(0, m_uNumLines-1);
  1281. m_nVScrollPos = (int)min(m_nVScrollPos, m_nVScrollMax-m_nMaxLinesPerPage+1);
  1282. sInfo.cbSize = sizeof(SCROLLINFO);
  1283. sInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
  1284. sInfo.nMin = 0;
  1285. sInfo.nMax = m_nVScrollMax;
  1286. sInfo.nPos = m_nVScrollPos;
  1287. sInfo.nPage = min(m_nMaxLinesPerPage, m_nVScrollMax+1);
  1288. SetScrollInfo (SB_VERT, &sInfo, TRUE);
  1289. // Horizontal scrollbar
  1290. m_nMaxColsPerPage = min(m_nMaxDisplayWidth+1, rcClient.Width() / m_xChar);
  1291. m_nHScrollMax = max(0, m_nMaxDisplayWidth-1);
  1292. m_nHScrollPos = min(m_nHScrollPos, m_nHScrollMax-m_nMaxColsPerPage+1);
  1293. sInfo.cbSize = sizeof(SCROLLINFO);
  1294. sInfo.fMask = SIF_POS | SIF_PAGE | SIF_RANGE;
  1295. sInfo.nMin = 0;
  1296. sInfo.nMax = m_nHScrollMax;
  1297. sInfo.nPos = m_nHScrollPos;
  1298. sInfo.nPage = min(m_nMaxColsPerPage, m_nHScrollMax+1);
  1299. SetScrollInfo (SB_HORZ, &sInfo, TRUE);
  1300. }
  1301. //
  1302. // Create 1 line of a hex-dump, given a buffer of BYTES
  1303. //
  1304. CString CFilePreviewCtrl::FormatHexLine(LPBYTE pData, int nBytesInLine, ULONG64 uLineOffset)
  1305. {
  1306. CString sResult;
  1307. CString str;
  1308. int i;
  1309. //print the hex address
  1310. str.Format(_T("%08X "), uLineOffset);
  1311. sResult += str;
  1312. //print hex data
  1313. for(i = 0; i < nBytesInLine; i++)
  1314. {
  1315. str.Format(_T("%02X "), pData[i]);
  1316. sResult += str;
  1317. }
  1318. //print some blanks if this isn't a full line
  1319. for(; i < m_nBytesPerLine; i++)
  1320. {
  1321. str.Format(_T(" "));
  1322. sResult += str;
  1323. }
  1324. //print a gap between the hex and ascii
  1325. sResult += _T(" ");
  1326. //print the ascii
  1327. for(i = 0; i < nBytesInLine; i++)
  1328. {
  1329. BYTE c = pData[i];
  1330. if(c < 32 || c > 128) c = '.';
  1331. str.Format( _T("%c"), c);
  1332. sResult += str;
  1333. }
  1334. //print some blanks if this isn't a full line
  1335. for(; i < m_nBytesPerLine; i++)
  1336. {
  1337. sResult += _T(" ");
  1338. }
  1339. return sResult;
  1340. }
  1341. //
  1342. // Draw 1 line to the display
  1343. //
  1344. void CFilePreviewCtrl::DrawHexLine(HDC hdc, DWORD nLineNo)
  1345. {
  1346. int nBytesPerLine = m_nBytesPerLine;
  1347. if(m_fm.GetSize() - nLineNo * m_nBytesPerLine < (UINT)m_nBytesPerLine)
  1348. nBytesPerLine= (DWORD)m_fm.GetSize() - nLineNo * m_nBytesPerLine;
  1349. //get data from our file mapping
  1350. LPBYTE ptr = m_fm.CreateView(nLineNo * m_nBytesPerLine, nBytesPerLine);
  1351. //convert the data into a one-line hex-dump
  1352. CString str = FormatHexLine(ptr, nBytesPerLine, nLineNo*m_nBytesPerLine );
  1353. //draw this line to the screen
  1354. TextOut(hdc, -(int)(m_nHScrollPos * m_xChar),
  1355. (nLineNo - m_nVScrollPos) * (m_yChar-1) , str, str.GetLength());
  1356. }
  1357. void CFilePreviewCtrl::DrawTextLine(HDC hdc, DWORD nLineNo)
  1358. {
  1359. CRect rcClient;
  1360. GetClientRect(&rcClient);
  1361. DWORD dwOffset = 0;
  1362. DWORD dwLength = 0;
  1363. {
  1364. CAutoLock lock(&m_csLock);
  1365. dwOffset = m_aTextLines[nLineNo];
  1366. if(nLineNo==m_uNumLines-1)
  1367. dwLength = (DWORD)m_fm.GetSize() - dwOffset;
  1368. else
  1369. dwLength = m_aTextLines[nLineNo+1]-dwOffset-1;
  1370. }
  1371. if(dwLength==0)
  1372. return;
  1373. //get data from our file mapping
  1374. LPBYTE ptr = m_fm.CreateView(dwOffset, dwLength);
  1375. //draw this line to the screen
  1376. CRect rcText;
  1377. rcText.left = -(int)(m_nHScrollPos * m_xChar);
  1378. rcText.top = (nLineNo - m_nVScrollPos) * m_yChar;
  1379. rcText.right = rcClient.right;
  1380. rcText.bottom = rcText.top + m_yChar;
  1381. DRAWTEXTPARAMS params;
  1382. memset(&params, 0, sizeof(DRAWTEXTPARAMS));
  1383. params.cbSize = sizeof(DRAWTEXTPARAMS);
  1384. params.iTabLength = m_xChar*m_cchTabLength;
  1385. DWORD dwFlags = DT_LEFT|DT_TOP|DT_SINGLELINE|DT_NOPREFIX|DT_EXPANDTABS;
  1386. if(m_TextEncoding==ENC_UTF8)
  1387. {
  1388. // Decode line
  1389. strconv_t strconv;
  1390. LPCWSTR szLine = strconv.utf82w((char*)ptr, dwLength-1);
  1391. DrawTextExW(hdc, (LPWSTR)szLine, -1, &rcText, dwFlags, &params);
  1392. }
  1393. else if(m_TextEncoding==ENC_UTF16_LE)
  1394. {
  1395. DrawTextExW(hdc, (WCHAR*)ptr, dwLength/2-1, &rcText,
  1396. dwFlags, &params);
  1397. }
  1398. else if(m_TextEncoding==ENC_UTF16_BE)
  1399. {
  1400. // Decode line
  1401. strconv_t strconv;
  1402. LPCWSTR szLine = strconv.w2w_be((WCHAR*)ptr, dwLength/2-1);
  1403. DrawTextExW(hdc, (LPWSTR)szLine, -1, &rcText, dwFlags, &params);
  1404. }
  1405. else // ASCII
  1406. {
  1407. DrawTextExA(hdc, (char*)ptr, dwLength-1, &rcText,
  1408. dwFlags, &params);
  1409. }
  1410. }
  1411. void CFilePreviewCtrl::DoPaintEmpty(HDC hDC)
  1412. {
  1413. RECT rcClient;
  1414. GetClientRect(&rcClient);
  1415. HFONT hOldFont = (HFONT)SelectObject(hDC, m_hFont);
  1416. FillRect(hDC, &rcClient, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1417. CRect rcText;
  1418. DrawTextEx(hDC, m_sEmptyMsg.GetBuffer(0), -1, &rcText, DT_CALCRECT, NULL);
  1419. rcText.MoveToX(rcClient.right/2-rcText.right/2);
  1420. DrawTextEx(hDC, m_sEmptyMsg.GetBuffer(0), -1, &rcText, DT_LEFT, NULL);
  1421. SelectObject(hDC, hOldFont);
  1422. }
  1423. void CFilePreviewCtrl::DoPaintText(HDC hDC)
  1424. {
  1425. HFONT hOldFont = (HFONT)SelectObject(hDC, m_hFont);
  1426. RECT rcClient;
  1427. GetClientRect(&rcClient);
  1428. HRGN hRgn = CreateRectRgn(0, 0, rcClient.right, rcClient.bottom);
  1429. SelectClipRgn(hDC, hRgn);
  1430. FillRect(hDC, &rcClient, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1431. int iPaintBeg = max(0, m_nVScrollPos); //only update the lines that
  1432. int iPaintEnd = (int)min(m_uNumLines, m_nVScrollPos + rcClient.bottom / m_yChar); //need updating!!!!!!!!!!!!!
  1433. if(rcClient.bottom % m_yChar) iPaintEnd++;
  1434. if(iPaintEnd > m_uNumLines) iPaintEnd--;
  1435. //
  1436. // Only paint what needs to be!
  1437. //
  1438. int i;
  1439. for(i = iPaintBeg; i < iPaintEnd; i++)
  1440. {
  1441. if(m_PreviewMode==PREVIEW_HEX)
  1442. DrawHexLine(hDC, i);
  1443. else
  1444. DrawTextLine(hDC, i);
  1445. }
  1446. SelectObject(hDC, hOldFont);
  1447. }
  1448. void CFilePreviewCtrl::DoPaintBitmap(HDC hDC)
  1449. {
  1450. RECT rcClient;
  1451. GetClientRect(&rcClient);
  1452. HRGN hRgn = CreateRectRgn(0, 0, rcClient.right, rcClient.bottom);
  1453. SelectClipRgn(hDC, hRgn);
  1454. FillRect(hDC, &rcClient, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1455. if(m_bmp.IsValid())
  1456. {
  1457. m_bmp.Draw(hDC, &rcClient);
  1458. }
  1459. else
  1460. {
  1461. DoPaintEmpty(hDC);
  1462. }
  1463. }
  1464. void CFilePreviewCtrl::DoPaintVideo(HDC hDC)
  1465. {
  1466. RECT rcClient;
  1467. GetClientRect(&rcClient);
  1468. HRGN hRgn = CreateRectRgn(0, 0, rcClient.right, rcClient.bottom);
  1469. SelectClipRgn(hDC, hRgn);
  1470. FillRect(hDC, &rcClient, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1471. if(m_video.IsValid())
  1472. {
  1473. m_video.DrawFrame(hDC, &rcClient);
  1474. }
  1475. else
  1476. {
  1477. DoPaintEmpty(hDC);
  1478. }
  1479. }
  1480. void CFilePreviewCtrl::DoPaint(HDC hDC)
  1481. {
  1482. if(m_PreviewMode==PREVIEW_TEXT ||
  1483. m_PreviewMode==PREVIEW_HEX)
  1484. {
  1485. DoPaintText(hDC);
  1486. }
  1487. else if(m_PreviewMode==PREVIEW_IMAGE)
  1488. {
  1489. DoPaintBitmap(hDC);
  1490. }
  1491. else if(m_PreviewMode==PREVIEW_VIDEO)
  1492. {
  1493. DoPaintVideo(hDC);
  1494. }
  1495. }
  1496. LRESULT CFilePreviewCtrl::OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1497. {
  1498. m_fm.Destroy();
  1499. bHandled = FALSE;
  1500. return 0;
  1501. }
  1502. LRESULT CFilePreviewCtrl::OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1503. {
  1504. SetupScrollbars();
  1505. InvalidateRect(NULL, FALSE);
  1506. UpdateWindow();
  1507. return 0;
  1508. }
  1509. LRESULT CFilePreviewCtrl::OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1510. {
  1511. SCROLLINFO info;
  1512. int nHScrollInc = 0;
  1513. int nOldHScrollPos = m_nHScrollPos;
  1514. switch (LOWORD(wParam))
  1515. {
  1516. case SB_LEFT:
  1517. m_nHScrollPos = 0;
  1518. break;
  1519. case SB_RIGHT:
  1520. m_nHScrollPos = m_nHScrollMax + 1;
  1521. break;
  1522. case SB_LINELEFT:
  1523. if(m_nHScrollPos > 0) --m_nHScrollPos;
  1524. break;
  1525. case SB_LINERIGHT:
  1526. m_nHScrollPos++;
  1527. break;
  1528. case SB_PAGELEFT:
  1529. m_nHScrollPos -= m_nMaxColsPerPage;
  1530. if(m_nHScrollPos > nOldHScrollPos)
  1531. m_nHScrollPos = 0;
  1532. break;
  1533. case SB_PAGERIGHT:
  1534. m_nHScrollPos += m_nMaxColsPerPage;
  1535. break;
  1536. case SB_THUMBPOSITION:
  1537. info.cbSize = sizeof(SCROLLINFO);
  1538. info.fMask = SIF_TRACKPOS;
  1539. GetScrollInfo(SB_HORZ, &info);
  1540. m_nHScrollPos = info.nTrackPos;
  1541. break;
  1542. case SB_THUMBTRACK:
  1543. info.cbSize = sizeof(SCROLLINFO);
  1544. info.fMask = SIF_TRACKPOS;
  1545. GetScrollInfo(SB_HORZ, &info);
  1546. m_nHScrollPos = info.nTrackPos;
  1547. break;
  1548. default:
  1549. nHScrollInc = 0;
  1550. }
  1551. //keep scroll position in range
  1552. if(m_nHScrollPos > m_nHScrollMax - m_nMaxColsPerPage + 1)
  1553. m_nHScrollPos = m_nHScrollMax - m_nMaxColsPerPage + 1;
  1554. nHScrollInc = m_nHScrollPos - nOldHScrollPos;
  1555. if (nHScrollInc)
  1556. {
  1557. //finally setup the actual scrollbar!
  1558. info.cbSize = sizeof(SCROLLINFO);
  1559. info.fMask = SIF_POS;
  1560. info.nPos = m_nHScrollPos;
  1561. SetScrollInfo(SB_HORZ, &info, TRUE);
  1562. InvalidateRect(NULL);
  1563. }
  1564. return 0;
  1565. }
  1566. LRESULT CFilePreviewCtrl::OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1567. {
  1568. // React to the various vertical scroll related actions.
  1569. // CAUTION:
  1570. // All sizes are in unsigned values, so be carefull
  1571. // when testing for < 0 etc
  1572. SCROLLINFO info;
  1573. int nVScrollInc;
  1574. int nOldVScrollPos = m_nVScrollPos;
  1575. switch (LOWORD(wParam))
  1576. {
  1577. case SB_TOP:
  1578. m_nVScrollPos = 0;
  1579. break;
  1580. case SB_BOTTOM:
  1581. m_nVScrollPos = m_nVScrollMax - m_nMaxLinesPerPage + 1;
  1582. break;
  1583. case SB_LINEUP:
  1584. if(m_nVScrollPos > 0) --m_nVScrollPos;
  1585. break;
  1586. case SB_LINEDOWN:
  1587. m_nVScrollPos++;
  1588. break;
  1589. case SB_PAGEUP:
  1590. m_nVScrollPos -= max(1, m_nMaxLinesPerPage);
  1591. if(m_nVScrollPos > nOldVScrollPos) m_nVScrollPos = 0;
  1592. break;
  1593. case SB_PAGEDOWN:
  1594. m_nVScrollPos += max(1, m_nMaxLinesPerPage);
  1595. break;
  1596. case SB_THUMBPOSITION:
  1597. info.cbSize = sizeof(SCROLLINFO);
  1598. info.fMask = SIF_TRACKPOS;
  1599. GetScrollInfo(SB_VERT, &info);
  1600. m_nVScrollPos = info.nTrackPos;
  1601. break;
  1602. case SB_THUMBTRACK:
  1603. info.cbSize = sizeof(SCROLLINFO);
  1604. info.fMask = SIF_TRACKPOS;
  1605. GetScrollInfo(SB_VERT, &info);
  1606. m_nVScrollPos = info.nTrackPos;
  1607. break;
  1608. default:
  1609. nVScrollInc = 0;
  1610. }
  1611. //keep scroll position in range
  1612. if(m_nVScrollPos > m_nVScrollMax - m_nMaxLinesPerPage+1)
  1613. m_nVScrollPos = m_nVScrollMax - m_nMaxLinesPerPage+1;
  1614. if(m_nVScrollPos<0)
  1615. m_nVScrollPos = 0;
  1616. nVScrollInc = m_nVScrollPos - nOldVScrollPos;
  1617. if (nVScrollInc)
  1618. {
  1619. //finally setup the actual scrollbar!
  1620. info.cbSize = sizeof(SCROLLINFO);
  1621. info.fMask = SIF_POS;
  1622. info.nPos = m_nVScrollPos;
  1623. SetScrollInfo(SB_VERT, &info, TRUE);
  1624. InvalidateRect(NULL);
  1625. }
  1626. return 0;
  1627. }
  1628. LRESULT CFilePreviewCtrl::OnEraseBkgnd(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1629. {
  1630. // Do nothing
  1631. return 0;
  1632. }
  1633. LRESULT CFilePreviewCtrl::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1634. {
  1635. PAINTSTRUCT ps;
  1636. HDC hDC = BeginPaint(&ps);
  1637. {
  1638. CMemoryDC memDC(hDC, ps.rcPaint);
  1639. if(m_fm.GetSize()==0)
  1640. DoPaintEmpty(memDC);
  1641. else
  1642. DoPaint(memDC);
  1643. }
  1644. EndPaint(&ps);
  1645. return 0;
  1646. }
  1647. LRESULT CFilePreviewCtrl::OnTimer(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1648. {
  1649. SetupScrollbars();
  1650. InvalidateRect(NULL);
  1651. return 0;
  1652. }
  1653. LRESULT CFilePreviewCtrl::OnComplete(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1654. {
  1655. KillTimer(0);
  1656. SetupScrollbars();
  1657. InvalidateRect(NULL);
  1658. return 0;
  1659. }
  1660. LRESULT CFilePreviewCtrl::OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1661. {
  1662. SetFocus();
  1663. return 0;
  1664. }
  1665. LRESULT CFilePreviewCtrl::OnRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1666. {
  1667. NMHDR nmhdr;
  1668. nmhdr.hwndFrom = m_hWnd;
  1669. nmhdr.code = NM_RCLICK;
  1670. nmhdr.idFrom = GetWindowLong(GWL_ID);
  1671. HWND hWndParent = GetParent();
  1672. ::SendMessage(hWndParent, WM_NOTIFY, 0, (LPARAM)&nmhdr);
  1673. return 0;
  1674. }
  1675. LRESULT CFilePreviewCtrl::OnMouseWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1676. {
  1677. if(m_PreviewMode!=PREVIEW_TEXT &&
  1678. m_PreviewMode!=PREVIEW_HEX)
  1679. return 0;
  1680. int nDistance = GET_WHEEL_DELTA_WPARAM(wParam)/WHEEL_DELTA;
  1681. int nLinesPerDelta = m_nMaxLinesPerPage!=0?m_nVScrollMax/m_nMaxLinesPerPage:0;
  1682. SCROLLINFO info;
  1683. memset(&info, 0, sizeof(SCROLLINFO));
  1684. info.cbSize = sizeof(SCROLLINFO);
  1685. info.fMask = SIF_ALL;
  1686. GetScrollInfo(SB_VERT, &info);
  1687. info.nPos -=nDistance*nLinesPerDelta;
  1688. SetScrollInfo(SB_VERT, &info, TRUE);
  1689. SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, info.nPos), 0);
  1690. return 0;
  1691. }