22#include " gdiplus.h"
33#include < Shlwapi.h>
44#include < math.h>
5+ #include < objidl.h> // Gdiplus
6+ #include < gdiplus.h> // Gdiplus
57
68#pragma comment(lib, "Shlwapi.lib")
9+ #pragma comment (lib, "Gdiplus.lib") // Gdiplus
10+ #pragma comment (lib, "Msimg32.lib") // AlphaBlend
711
812using namespace Gdiplus ;
913
10- void ReadData (IStream *pStream, BYTE *data, ULONG length) {
14+ inline void ReadData (IStream *pStream, BYTE *data, ULONG length) {
1115 ULONG read, total = 0 ;
1216 HRESULT hr;
1317
@@ -17,51 +21,66 @@ void ReadData(IStream *pStream, BYTE *data, ULONG length) {
1721 } while (total < length && hr == S_OK );
1822}
1923
20- UINT ReadUInt32 (IStream *pStream) {
24+ inline UINT ReadUInt32 (IStream *pStream) {
2125 BYTE b[4 ];
2226 ReadData (pStream, b, 4 );
2327 return b[0 ] << 24 | b[1 ] << 16 | b[2 ] << 8 | b[3 ];
2428}
2529
26- SHORT ReadInt16 (IStream *pStream) {
30+ inline ULONG64 ReadUInt64 (IStream *pStream) {
31+ BYTE b[8 ];
32+ ReadData (pStream, b, 8 );
33+ return (ULONG64 )b[0 ] << 56 | (ULONG64 )b[1 ] << 48 | (ULONG64 )b[2 ] << 40 | (ULONG64 )b[3 ] << 32 | (ULONG64 )b[4 ] << 24 | (ULONG64 )b[5 ] << 16 | (ULONG64 )b[6 ] << 8 | (ULONG64 )b[7 ];
34+ }
35+
36+ inline SHORT ReadInt16 (IStream *pStream) {
2737 BYTE b[2 ];
2838 ReadData (pStream, b, 2 );
2939 return b[0 ] << 8 | b[1 ];
3040}
3141
32- USHORT ReadUInt16 (IStream *pStream) {
42+ inline USHORT ReadUInt16 (IStream *pStream) {
3343 BYTE b[2 ];
3444 ReadData (pStream, b, 2 );
3545 return b[0 ] << 8 | b[1 ];
3646}
3747
38- BYTE ReadByte (IStream *pStream) {
48+ inline BYTE ReadByte (IStream *pStream) {
3949 BYTE b;
4050 ReadData (pStream, &b, 1 );
4151 return b;
4252}
4353
44- void Seek (IStream *pStream, int offset, DWORD origin) {
45- LARGE_INTEGER pos;
46- pos.QuadPart = offset;
47- pStream->Seek (pos, origin, NULL );
54+ inline LONGLONG ReadSectionLength (IStream *pStream, int version = 1 ) {
55+ if (version == 1 ) {
56+ return (LONGLONG )ReadUInt32 (pStream);
57+ } else {
58+ return (LONGLONG )ReadUInt64 (pStream);
59+ }
4860}
4961
50- UINT Tell (IStream *pStream) {
62+ inline void Seek (IStream *pStream, LONGLONG offset, DWORD origin) {
63+ if (offset > 0 ) {
64+ LARGE_INTEGER pos;
65+ pos.QuadPart = offset;
66+ pStream->Seek (pos, origin, NULL );
67+ }
68+ }
69+
70+ inline ULONGLONG Tell (IStream *pStream) {
5171 LARGE_INTEGER pos;
5272 ULARGE_INTEGER newPos;
5373 pos.QuadPart = 0 ;
5474 pStream->Seek (pos, STREAM_SEEK_CUR , &newPos);
55- return ( UINT ) newPos.QuadPart ;
75+ return newPos.QuadPart ;
5676}
5777
5878HBITMAP GetPSDThumbnail (IStream* stream) {
5979 HBITMAP result = NULL ;
6080 UINT signature = ReadUInt32 (stream);
6181 USHORT version = ReadUInt16 (stream);
6282
63- if (signature != 0x38425053 || version != 1 )
64- return NULL ;
83+ if (signature != 0x38425053 || (version != 1 && version != 2 )) return NULL ;
6584
6685 Seek (stream, 6 , STREAM_SEEK_CUR );
6786
@@ -70,46 +89,48 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
7089 int width = ReadUInt32 (stream);
7190 USHORT bitsPerChannel = ReadUInt16 (stream);
7291 USHORT colorMode = ReadUInt16 (stream);
73- UINT length = ReadUInt32 (stream);
92+ int maxSize = version == 1 ? 30000 : 300000 ;
93+ if (width > maxSize || height > maxSize) return NULL ;
7494
75- if (length > 0 ) {
76- Seek (stream, length, STREAM_SEEK_CUR );
77- }
95+ // color mode data
96+ auto colorModeLength = ReadSectionLength (stream );
97+ Seek (stream, colorModeLength, STREAM_SEEK_CUR );
7898
79- UINT resourcesLength = ReadUInt32 (stream);
80- UINT reasourceOffset = Tell (stream);
81- UINT thumbnailOffset = 0 ;
82- UINT resourceAdvanced = 0 ;
99+ // image resources
100+ auto resourcesLength = ReadSectionLength (stream);
101+ auto reasourceOffset = Tell (stream);
102+ ULONGLONG resourceEnd = reasourceOffset + resourcesLength;
103+ LONGLONG thumbnailOffset = 0 ;
104+ ULONG thumbnailLength = 0 ;
83105
84- while (resourcesLength > resourceAdvanced ) {
85- Seek (stream, 4 , STREAM_SEEK_CUR );
106+ while (Tell (stream) < resourceEnd ) {
107+ Seek (stream, 4 , STREAM_SEEK_CUR ); // signature
86108
87109 USHORT id = ReadUInt16 (stream);
88- BYTE strl = ReadByte (stream);
89110
90- Seek (stream, strl % 2 == 0 ? strl + 1 : strl, STREAM_SEEK_CUR );
111+ BYTE nameLength = ReadByte (stream); // name
112+ Seek (stream, ((nameLength + 1 ) % 2 ) ? nameLength + 1 : nameLength, STREAM_SEEK_CUR );
91113
92- length = ReadUInt32 (stream);
114+ auto length = ReadSectionLength (stream);
93115
94116 if (id == 1036 ) {
95117 thumbnailOffset = Tell (stream);
118+ thumbnailLength = (ULONG )length;
96119 break ;
97120 }
98121
99- Seek (stream, length % 2 ? length + 1 : length, STREAM_SEEK_CUR );
100-
101- resourceAdvanced += 6 + 1 + (strl % 2 == 0 ? strl + 1 : strl) +
102- 4 + (length % 2 ? length + 1 : length);
122+ Seek (stream, length, STREAM_SEEK_CUR );
123+ if (Tell (stream) % 2 ) Seek (stream, 1 , STREAM_SEEK_CUR );
103124 }
104125
105126 // read composite image
106- if (colorMode == 3 && ((width <= 256 && height <= 256 ) || !thumbnailOffset)) {
127+ if (false && colorMode == 3 && ((width <= 256 && height <= 256 ) || !thumbnailOffset)) {
107128 Seek (stream, reasourceOffset + resourcesLength, STREAM_SEEK_SET );
108129
109- UINT layerAndMaskInfoLength = ReadUInt32 (stream);
110- UINT layerAndMastInfoOffset = Tell (stream);
130+ auto layerAndMaskInfoLength = ReadSectionLength (stream);
131+ auto layerAndMastInfoOffset = Tell (stream);
111132
112- UINT layerInfoLength = ReadUInt32 (stream);
133+ auto layerInfoLength = ReadSectionLength (stream);
113134 SHORT layerCount = ReadInt16 (stream);
114135 bool globalAlpha = layerCount < 0 ;
115136
@@ -160,8 +181,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
160181 for (int y = 0 ; y < height; y++, li++) {
161182 Seek (stream, lengths[li], STREAM_SEEK_CUR );
162183 }
163- }
164- else {
184+ } else {
165185 for (int y = 0 , p = offset; y < height; y++, li++) {
166186 int length = lengths[li];
167187 ReadData (stream, buffer, length);
@@ -177,8 +197,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
177197 data[p] = value;
178198 p += step;
179199 }
180- }
181- else { // header < 128
200+ } else { // header < 128
182201 for (int j = 0 ; j <= header; j++) {
183202 data[p] = buffer[++i];
184203 p += step;
@@ -224,8 +243,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
224243 if (width > height) {
225244 thumbWidth = 256 ;
226245 thumbHeight = height * thumbWidth / width;
227- }
228- else {
246+ } else {
229247 thumbHeight = 256 ;
230248 thumbWidth = width * thumbHeight / height;
231249 }
@@ -253,8 +271,7 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
253271 DeleteDC (srcDC);
254272 DeleteDC (memDC);
255273 ReleaseDC (NULL , dc);
256- }
257- else {
274+ } else {
258275 result = CreateBitmap (width, height, 1 , 32 , data);
259276 }
260277 }
@@ -272,9 +289,9 @@ HBITMAP GetPSDThumbnail(IStream* stream) {
272289 if (Ok == GdiplusStartup (&token, &input, NULL )) {
273290 Seek (stream, 4 + 4 + 4 + 4 + 4 + 4 + 2 + 2 , STREAM_SEEK_CUR );
274291
275- BYTE *data = new BYTE [length];
276- ReadData (stream, data, length );
277- IStream *memory = SHCreateMemStream (data, length );
292+ BYTE *data = new BYTE [thumbnailLength]; // TODO: should this be freed?
293+ ReadData (stream, data, thumbnailLength );
294+ IStream *memory = SHCreateMemStream (data, thumbnailLength );
278295
279296 if (memory) {
280297 Seek (memory, 0 , STREAM_SEEK_SET );
0 commit comments