[Windows] Fix driver version detection of AMD RDNA+ GPU on Windows 10
[xbmc.git] / xbmc / pictures / JpegParse.cpp
blob718ac5426a8fe226921f57df1bb6dc957384d4ce
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 //--------------------------------------------------------------------------
10 // This module gathers information about a digital image file. This includes:
11 // - File name and path
12 // - File size
13 // - Resolution (if available)
14 // - IPTC information (if available)
15 // - EXIF information (if available)
16 // All gathered information is stored in a vector of 'description' and 'value'
17 // pairs (where both description and value fields are of CStdString types).
18 //--------------------------------------------------------------------------
20 #include "JpegParse.h"
22 #include "filesystem/File.h"
24 #ifdef TARGET_WINDOWS
25 #include <windows.h>
26 #else
27 #include <memory.h>
28 #include <cstring>
29 typedef unsigned char BYTE;
30 #endif
32 #ifndef min
33 #define min(a,b) (a)>(b)?(b):(a)
34 #endif
36 using namespace XFILE;
38 //--------------------------------------------------------------------------
39 #define JPEG_PARSE_STRING_ID_BASE 21500
40 enum {
41 ProcessUnknown = JPEG_PARSE_STRING_ID_BASE,
42 ProcessSof0,
43 ProcessSof1,
44 ProcessSof2,
45 ProcessSof3,
46 ProcessSof5,
47 ProcessSof6,
48 ProcessSof7,
49 ProcessSof9,
50 ProcessSof10,
51 ProcessSof11,
52 ProcessSof13,
53 ProcessSof14,
54 ProcessSof15,
60 //--------------------------------------------------------------------------
61 // Constructor
62 //--------------------------------------------------------------------------
63 CJpegParse::CJpegParse():
64 m_SectionBuffer(NULL)
66 memset(&m_ExifInfo, 0, sizeof(m_ExifInfo));
67 memset(&m_IPTCInfo, 0, sizeof(m_IPTCInfo));
70 //--------------------------------------------------------------------------
71 // Process a SOFn marker. This is useful for the image dimensions
72 //--------------------------------------------------------------------------
73 void CJpegParse::ProcessSOFn (void)
75 m_ExifInfo.Height = CExifParse::Get16(m_SectionBuffer+3);
76 m_ExifInfo.Width = CExifParse::Get16(m_SectionBuffer+5);
78 unsigned char num_components = m_SectionBuffer[7];
79 if (num_components != 3)
81 m_ExifInfo.IsColor = 0;
83 else
85 m_ExifInfo.IsColor = 1;
90 //--------------------------------------------------------------------------
91 // Read a section from a JPEG file. Note that this function allocates memory.
92 // It must be called in pair with ReleaseSection
93 //--------------------------------------------------------------------------
94 bool CJpegParse::GetSection (CFile& infile, const unsigned short sectionLength)
96 if (sectionLength < 2)
98 printf("JpgParse: invalid section length");
99 return false;
102 m_SectionBuffer = new unsigned char[sectionLength];
103 if (m_SectionBuffer == NULL)
105 printf("JpgParse: could not allocate memory");
106 return false;
108 // Store first two pre-read bytes.
109 m_SectionBuffer[0] = (unsigned char)(sectionLength >> 8);
110 m_SectionBuffer[1] = (unsigned char)(sectionLength & 0x00FF);
112 unsigned int len = (unsigned int)sectionLength;
114 size_t bytesRead = infile.Read(m_SectionBuffer+sizeof(sectionLength), len-sizeof(sectionLength));
115 if (bytesRead != sectionLength-sizeof(sectionLength))
117 printf("JpgParse: premature end of file?");
118 ReleaseSection();
119 return false;
121 return true;
124 //--------------------------------------------------------------------------
125 // Deallocate memory allocated in GetSection. This function must always
126 // be paired by a preceding GetSection call.
127 //--------------------------------------------------------------------------
128 void CJpegParse::ReleaseSection (void)
130 delete[] m_SectionBuffer;
131 m_SectionBuffer = NULL;
134 //--------------------------------------------------------------------------
135 // Parse the marker stream until SOS or EOI is seen; infile has already been
136 // successfully open
137 //--------------------------------------------------------------------------
138 bool CJpegParse::ExtractInfo (CFile& infile)
140 // Get file marker (two bytes - must be 0xFFD8 for JPEG files
141 BYTE a;
142 size_t bytesRead = infile.Read(&a, sizeof(BYTE));
143 if ((bytesRead != sizeof(BYTE)) || (a != 0xFF))
145 return false;
147 bytesRead = infile.Read(&a, sizeof(BYTE));
148 if ((bytesRead != sizeof(BYTE)) || (a != M_SOI))
150 return false;
153 for(;;)
155 BYTE marker = 0;
156 for (a=0; a<7; a++) {
157 bytesRead = infile.Read(&marker, sizeof(BYTE));
158 if (marker != 0xFF)
159 break;
161 if (a >= 6)
163 printf("JpgParse: too many padding bytes");
164 return false;
166 marker = 0;
169 // Read the length of the section.
170 unsigned short itemlen = 0;
171 bytesRead = infile.Read(&itemlen, sizeof(itemlen));
172 itemlen = CExifParse::Get16(&itemlen);
174 if ((bytesRead != sizeof(itemlen)) || (itemlen < sizeof(itemlen)))
176 printf("JpgParse: invalid marker");
177 return false;
180 switch(marker)
182 case M_SOS: // stop before hitting compressed data
183 return true;
185 case M_EOI: // in case it's a tables-only JPEG stream
186 printf("JpgParse: No image in jpeg!");
187 return false;
188 break;
190 case M_COM: // Comment section
191 GetSection(infile, itemlen);
192 if (m_SectionBuffer != NULL)
194 // CExifParse::FixComment(comment); // Ensure comment is printable
195 unsigned short length = min(itemlen - 2, MAX_COMMENT);
196 strncpy(m_ExifInfo.FileComment, (char *)&m_SectionBuffer[2], length);
197 m_ExifInfo.FileComment[length] = '\0';
199 ReleaseSection();
200 break;
202 case M_SOF0:
203 case M_SOF1:
204 case M_SOF2:
205 case M_SOF3:
206 case M_SOF5:
207 case M_SOF6:
208 case M_SOF7:
209 case M_SOF9:
210 case M_SOF10:
211 case M_SOF11:
212 case M_SOF13:
213 case M_SOF14:
214 case M_SOF15:
215 GetSection(infile, itemlen);
216 if ((m_SectionBuffer != NULL) && (itemlen >= 7))
218 ProcessSOFn();
219 m_ExifInfo.Process = marker;
221 ReleaseSection();
222 break;
224 case M_IPTC:
225 GetSection(infile, itemlen);
226 if (m_SectionBuffer != NULL)
228 CIptcParse::Process(m_SectionBuffer, itemlen, &m_IPTCInfo);
230 ReleaseSection();
231 break;
233 case M_EXIF:
234 // Seen files from some 'U-lead' software with Vivitar scanner
235 // that uses marker 31 for non exif stuff. Thus make sure
236 // it says 'Exif' in the section before treating it as exif.
237 GetSection(infile, itemlen);
238 if (m_SectionBuffer != NULL)
240 CExifParse exif;
241 exif.Process(m_SectionBuffer, itemlen, &m_ExifInfo);
243 ReleaseSection();
244 break;
246 case M_JFIF:
247 // Regular jpegs always have this tag, exif images have the exif
248 // marker instead, although ACDsee will write images with both markers.
249 // this program will re-create this marker on absence of exif marker.
250 // hence no need to keep the copy from the file.
251 // fall through to default case
252 default:
253 // Skip any other sections.
254 GetSection(infile, itemlen);
255 ReleaseSection();
256 break;
259 return true;
262 //--------------------------------------------------------------------------
263 // Process a file. Check if it is JPEG. Extract exif/iptc info if it is.
264 //--------------------------------------------------------------------------
265 bool CJpegParse::Process (const char *picFileName)
267 CFile file;
269 if (!file.Open(picFileName))
270 return false;
272 // File exists and successfully opened. Start processing
273 // Gather all information about the file
275 /* // Get file name...
276 CStdString tmp, urlFName, path;
277 CURL url(picFileName);
278 url.GetURLWithoutUserDetails(urlFName);
279 CUtil::Split(urlFName, path, tmp);
280 m_JpegInfo[SLIDESHOW_FILE_NAME] = tmp;
281 // ...then path...
282 m_JpegInfo[SLIDESHOW_FILE_PATH] = path;
284 // ...then size...
285 __stat64 fileStat;
286 CFile::Stat(picFileName, &fileStat);
287 float fileSize = (float)fileStat.st_size;
288 tmp = "";
289 if (fileSize > 1024)
291 fileSize /= 1024;
292 tmp = "KB";
294 if (fileSize > 1024)
296 fileSize /= 1024;
297 tmp = "MB";
299 if (fileSize > 1024)
301 fileSize /= 1024;
302 tmp = "GB";
304 tmp.Format("%.2f %s", fileSize, tmp);
305 m_JpegInfo[SLIDESHOW_FILE_SIZE] = tmp;
307 // ...then date and time...
308 CDateTime date((time_t)fileStat.st_mtime);
309 tmp.Format("%s %s", date.GetAsLocalizedDate(), date.GetAsLocalizedTime());
310 m_JpegInfo[SLIDESHOW_FILE_DATE] = tmp;*/
312 bool result = ExtractInfo(file);
313 file.Close();
314 return result;