Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qedidparser.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 Pier Luigi Fiorini <pierluigi.fiorini@gmail.com>
2// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtCore/QFile>
6#include <QtCore/QByteArrayView>
7
8#include "qedidparser_p.h"
10
11#define EDID_DESCRIPTOR_ALPHANUMERIC_STRING 0xfe
12#define EDID_DESCRIPTOR_PRODUCT_NAME 0xfc
13#define EDID_DESCRIPTOR_SERIAL_NUMBER 0xff
14
15#define EDID_DATA_BLOCK_COUNT 4
16#define EDID_OFFSET_DATA_BLOCKS 0x36
17#define EDID_OFFSET_LAST_BLOCK 0x6c
18#define EDID_OFFSET_PNP_ID 0x08
19#define EDID_OFFSET_SERIAL 0x0c
20#define EDID_PHYSICAL_WIDTH 0x15
21#define EDID_OFFSET_PHYSICAL_HEIGHT 0x16
22#define EDID_TRANSFER_FUNCTION 0x17
23#define EDID_FEATURE_SUPPORT 0x18
24#define EDID_CHROMATICITIES_BLOCK 0x19
25
27
28using namespace Qt::StringLiterals;
29
31{
33
34 const QString fileName = "/usr/share/hwdata/pnp.ids"_L1;
37 return result;
38
39 // On Ubuntu 20.04 the longest line in the file is 85 bytes, so this
40 // leaves plenty of room...
41 constexpr int MaxLineSize = 512;
42 char buf[MaxLineSize];
43
44 while (!file.atEnd()) {
45 auto read = file.readLine(buf, MaxLineSize);
46 if (read < 0 || read == MaxLineSize) // read error
47 break;
48
49 QByteArrayView line(buf, read - 1); // -1 to remove the trailing newline
50 if (line.isEmpty())
51 continue;
52
53 if (line.startsWith('#'))
54 continue;
55
56 auto tabPosition = line.indexOf('\t');
57 if (tabPosition <= 0) // no vendor id
58 continue;
59 if (tabPosition + 1 == line.size()) // no vendor name
60 continue;
61
62 if (line.first(tabPosition) == id) {
63 auto vendor = line.sliced(tabPosition + 1);
64 result = QString::fromUtf8(vendor.data(), vendor.size());
65 break;
66 }
67 }
68
69 return result;
70}
71
73{
74 const quint8 *data = reinterpret_cast<const quint8 *>(blob.constData());
75 const size_t length = blob.size();
76
77 // Verify header
78 if (length < 128)
79 return false;
80 if (data[0] != 0x00 || data[1] != 0xff)
81 return false;
82
83 /* Decode the PNP ID from three 5 bit words packed into 2 bytes
84 * /--08--\/--09--\
85 * 7654321076543210
86 * |\---/\---/\---/
87 * R C1 C2 C3 */
88 char pnpId[3];
89 pnpId[0] = 'A' + ((data[EDID_OFFSET_PNP_ID] & 0x7c) / 4) - 1;
90 pnpId[1] = 'A' + ((data[EDID_OFFSET_PNP_ID] & 0x3) * 8) + ((data[EDID_OFFSET_PNP_ID + 1] & 0xe0) / 32) - 1;
91 pnpId[2] = 'A' + (data[EDID_OFFSET_PNP_ID + 1] & 0x1f) - 1;
92
93 // Clear manufacturer
95
96 // Serial number, will be overwritten by an ASCII descriptor
97 // when and if it will be found
99 + (data[EDID_OFFSET_SERIAL + 1] << 8)
100 + (data[EDID_OFFSET_SERIAL + 2] << 16)
101 + (data[EDID_OFFSET_SERIAL + 3] << 24);
102 if (serial > 0)
104 else
106
107 // Parse EDID data
108 for (int i = 0; i < EDID_DATA_BLOCK_COUNT; ++i) {
109 const uint offset = EDID_OFFSET_DATA_BLOCKS + i * 18;
110
111 if (data[offset] != 0 || data[offset + 1] != 0 || data[offset + 2] != 0)
112 continue;
113
115 model = parseEdidString(&data[offset + 5]);
117 identifier = parseEdidString(&data[offset + 5]);
119 serialNumber = parseEdidString(&data[offset + 5]);
120 }
121
122 // Try to use cache first because it is potentially more updated
124
125 if (manufacturer.isEmpty()) {
126 // Find the manufacturer from the vendor lookup table
127 const auto compareVendorId = [](const VendorTable &vendor, const char *str)
128 {
129 return strncmp(vendor.id, str, 3) < 0;
130 };
131
132 const auto b = std::begin(q_edidVendorTable);
133 const auto e = std::end(q_edidVendorTable);
134 auto it = std::lower_bound(b,
135 e,
136 pnpId,
137 compareVendorId);
138
139 if (it != e && strncmp(it->id, pnpId, 3) == 0)
141 }
142
143 // If we don't know the manufacturer, fallback to PNP ID
144 if (manufacturer.isEmpty())
145 manufacturer = QString::fromUtf8(pnpId, std::size(pnpId));
146
147 // Physical size
149
150 // Gamma and transfer function
151 const uint igamma = data[EDID_TRANSFER_FUNCTION];
152 if (igamma != 0xff) {
153 gamma = 1.0 + (igamma / 100.0f);
154 useTables = false;
155 } else {
156 gamma = 0.0; // Defined in DI-EXT
157 useTables = true;
158 }
160
161 // Chromaticities
162 int rx = (data[EDID_CHROMATICITIES_BLOCK] >> 6) & 0x03;
163 int ry = (data[EDID_CHROMATICITIES_BLOCK] >> 4) & 0x03;
164 int gx = (data[EDID_CHROMATICITIES_BLOCK] >> 2) & 0x03;
165 int gy = (data[EDID_CHROMATICITIES_BLOCK] >> 0) & 0x03;
166 int bx = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 6) & 0x03;
167 int by = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 4) & 0x03;
168 int wx = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 2) & 0x03;
169 int wy = (data[EDID_CHROMATICITIES_BLOCK + 1] >> 0) & 0x03;
170 rx |= data[EDID_CHROMATICITIES_BLOCK + 2] << 2;
171 ry |= data[EDID_CHROMATICITIES_BLOCK + 3] << 2;
172 gx |= data[EDID_CHROMATICITIES_BLOCK + 4] << 2;
173 gy |= data[EDID_CHROMATICITIES_BLOCK + 5] << 2;
174 bx |= data[EDID_CHROMATICITIES_BLOCK + 6] << 2;
175 by |= data[EDID_CHROMATICITIES_BLOCK + 7] << 2;
176 wx |= data[EDID_CHROMATICITIES_BLOCK + 8] << 2;
177 wy |= data[EDID_CHROMATICITIES_BLOCK + 9] << 2;
178
179 redChromaticity.setX(rx * (1.0f / 1024.0f));
180 redChromaticity.setY(ry * (1.0f / 1024.0f));
181 greenChromaticity.setX(gx * (1.0f / 1024.0f));
182 greenChromaticity.setY(gy * (1.0f / 1024.0f));
183 blueChromaticity.setX(bx * (1.0f / 1024.0f));
184 blueChromaticity.setY(by * (1.0f / 1024.0f));
185 whiteChromaticity.setX(wx * (1.0f / 1024.0f));
186 whiteChromaticity.setY(wy * (1.0f / 1024.0f));
187
188 // Find extensions
189 for (uint i = 1; i < length / 128; ++i) {
190 uint extensionId = data[i * 128];
191 if (extensionId == 0x40) { // DI-EXT
192 // 0x0E (sub-pixel layout)
193 // 0x20->0x22 (bits per color)
194 // 0x51->0x7e Transfer characteristics
195 const uchar desc = data[i * 128 + 0x51];
196 const uchar len = desc & 0x3f;
197 if ((desc & 0xc0) == 0x40) {
198 if (len > 45)
199 return false;
200 QList<uint16_t> whiteTRC;
201 whiteTRC.reserve(len + 1);
202 for (uint j = 0; j < len; ++j)
203 whiteTRC[j] = data[0x52 + j] * 0x101;
204 whiteTRC[len] = 0xffff;
205 tables.append(whiteTRC);
206 } else if ((desc & 0xc0) == 0x80) {
207 if (len > 15)
208 return false;
209 QList<uint16_t> redTRC;
210 QList<uint16_t> greenTRC;
211 QList<uint16_t> blueTRC;
212 blueTRC.reserve(len + 1);
213 greenTRC.reserve(len + 1);
214 redTRC.reserve(len + 1);
215 for (uint j = 0; j < len; ++j)
216 blueTRC[j] = data[0x52 + j] * 0x101;
217 blueTRC[len] = 0xffff;
218 for (uint j = 0; j < len; ++j)
219 greenTRC[j] = data[0x61 + j] * 0x101;
220 greenTRC[len] = 0xffff;
221 for (uint j = 0; j < len; ++j)
222 redTRC[j] = data[0x70 + j] * 0x101;
223 redTRC[len] = 0xffff;
224 tables.append(redTRC);
225 tables.append(greenTRC);
226 tables.append(blueTRC);
227 }
228 }
229 }
230
231 return true;
232}
233
234QString QEdidParser::parseEdidString(const quint8 *data)
235{
236 QByteArray buffer(reinterpret_cast<const char *>(data), 13);
237
238 for (int i = 0; i < buffer.size(); ++i) {
239 // If there are less than 13 characters in the string, the string
240 // is terminated with the ASCII code ‘0Ah’ (line feed) and padded
241 // with ASCII code ‘20h’ (space). See EDID 1.4, sections 3.10.3.1,
242 // 3.10.3.2, and 3.10.3.4.
243 if (buffer[i] == '\n') {
244 buffer.truncate(i);
245 break;
246 }
247
248 // Replace non-printable characters with dash
249 if (buffer[i] < '\040' || buffer[i] > '\176')
250 buffer[i] = '-';
251 }
252
254}
255
\inmodule QtCore
Definition qbytearray.h:57
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
Definition qbytearray.h:494
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
Definition qbytearray.h:124
QSizeF physicalSize
QPointF blueChromaticity
QPointF redChromaticity
QList< QList< uint16_t > > tables
QString model
QPointF whiteChromaticity
QString manufacturer
QPointF greenChromaticity
bool parse(const QByteArray &blob)
QString identifier
QString serialNumber
bool atEnd() const override
Returns true if the end of the file has been reached; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
QFILE_MAYBE_NODISCARD bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:904
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes,...
void append(parameter_type t)
Definition qlist.h:458
constexpr void setY(qreal y) noexcept
Sets the y coordinate of this point to the given finite y coordinate.
Definition qpoint.h:358
constexpr void setX(qreal x) noexcept
Sets the x coordinate of this point to the given finite x coordinate.
Definition qpoint.h:353
\inmodule QtCore
Definition qsize.h:208
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype indexOf(QLatin1StringView s, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4517
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5455
QString sliced(qsizetype pos) const &
Definition qstring.h:394
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:6018
QString first(qsizetype n) const &
Definition qstring.h:390
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString str
[2]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define EDID_DESCRIPTOR_SERIAL_NUMBER
#define EDID_FEATURE_SUPPORT
#define EDID_CHROMATICITIES_BLOCK
#define EDID_TRANSFER_FUNCTION
static QString lookupVendorIdInSystemDatabase(QByteArrayView id)
#define EDID_OFFSET_SERIAL
#define EDID_DESCRIPTOR_ALPHANUMERIC_STRING
#define EDID_OFFSET_PNP_ID
#define EDID_OFFSET_PHYSICAL_HEIGHT
#define EDID_DESCRIPTOR_PRODUCT_NAME
#define EDID_PHYSICAL_WIDTH
#define EDID_DATA_BLOCK_COUNT
#define EDID_OFFSET_DATA_BLOCKS
static const VendorTable q_edidVendorTable[]
GLboolean GLboolean GLboolean b
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint buffer
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint GLintptr offset
GLuint64EXT * result
[6]
GLenum GLsizei len
GLbyte by
unsigned int quint32
Definition qtypes.h:50
unsigned char uchar
Definition qtypes.h:32
unsigned int uint
Definition qtypes.h:34
unsigned char quint8
Definition qtypes.h:46
ReturnedValue read(const char *data)
QFile file
[0]
p ry()++
p rx()++
const char id[4]