graphics() macOS new XML parser
This commit is contained in:
parent
cd46226ad5
commit
09775cd5bd
@ -989,7 +989,7 @@ function diskLayout(callback) {
|
||||
if (sizeStr) {
|
||||
let sizeValue = 0;
|
||||
if (sizeStr.indexOf('(') >= 0) {
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, ''));
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/ /g, ''));
|
||||
}
|
||||
if (!sizeValue) {
|
||||
sizeValue = parseInt(sizeStr);
|
||||
@ -1037,7 +1037,7 @@ function diskLayout(callback) {
|
||||
if (sizeStr) {
|
||||
let sizeValue = 0;
|
||||
if (sizeStr.indexOf('(') >= 0) {
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, ''));
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/ /g, ''));
|
||||
}
|
||||
if (!sizeValue) {
|
||||
sizeValue = parseInt(sizeStr);
|
||||
@ -1082,7 +1082,7 @@ function diskLayout(callback) {
|
||||
if (sizeStr) {
|
||||
let sizeValue = 0;
|
||||
if (sizeStr.indexOf('(') >= 0) {
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, ''));
|
||||
sizeValue = parseInt(sizeStr.match(/\(([^)]+)\)/)[1].replace(/\./g, '').replace(/,/g, '').replace(/ /g, ''));
|
||||
}
|
||||
if (!sizeValue) {
|
||||
sizeValue = parseInt(sizeStr);
|
||||
|
||||
250
lib/graphics.js
250
lib/graphics.js
@ -57,7 +57,7 @@ const videoTypes = {
|
||||
};
|
||||
|
||||
function getVendorFromModel(model) {
|
||||
const diskManufacturers = [
|
||||
const manufacturers = [
|
||||
{ pattern: '^LG.+', manufacturer: 'LG' },
|
||||
{ pattern: '^BENQ.+', manufacturer: 'BenQ' },
|
||||
{ pattern: '^ASUS.+', manufacturer: 'Asus' },
|
||||
@ -76,12 +76,15 @@ function getVendorFromModel(model) {
|
||||
{ pattern: '^LENOVO.+', manufacturer: 'Lenovo' },
|
||||
{ pattern: 'COMPAQ.+', manufacturer: 'Compaq' },
|
||||
{ pattern: 'APPLE.+', manufacturer: 'Apple' },
|
||||
{ pattern: 'INTEL.+', manufacturer: 'Intel' },
|
||||
{ pattern: 'AMD.+', manufacturer: 'AMD' },
|
||||
{ pattern: 'NVIDIA.+', manufacturer: 'NVDIA' },
|
||||
];
|
||||
|
||||
let result = '';
|
||||
if (model) {
|
||||
model = model.toUpperCase();
|
||||
diskManufacturers.forEach((manufacturer) => {
|
||||
manufacturers.forEach((manufacturer) => {
|
||||
const re = RegExp(manufacturer.pattern);
|
||||
if (re.test(model)) { result = manufacturer.manufacturer; }
|
||||
});
|
||||
@ -89,166 +92,97 @@ function getVendorFromModel(model) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getVendorFromId(id) {
|
||||
const vendors = {
|
||||
'610': 'Apple',
|
||||
'1e6d': 'LG',
|
||||
'10ac': 'DELL',
|
||||
'4dd9': 'Sony',
|
||||
'38a3': 'NEC',
|
||||
};
|
||||
return vendors[id] || '';
|
||||
}
|
||||
|
||||
function getMetalVersion(id) {
|
||||
const families = {
|
||||
'spdisplays_mtlgpufamilymac1': 'mac1',
|
||||
'spdisplays_mtlgpufamilymac2': 'mac2',
|
||||
'spdisplays_mtlgpufamilyapple1': 'apple1',
|
||||
'spdisplays_mtlgpufamilyapple2': 'apple2',
|
||||
'spdisplays_mtlgpufamilyapple3': 'apple3',
|
||||
'spdisplays_mtlgpufamilyapple4': 'apple4',
|
||||
'spdisplays_mtlgpufamilyapple5': 'apple5',
|
||||
'spdisplays_mtlgpufamilyapple6': 'apple6',
|
||||
'spdisplays_mtlgpufamilyapple7': 'apple7',
|
||||
};
|
||||
return families[id] || '';
|
||||
}
|
||||
|
||||
function graphics(callback) {
|
||||
|
||||
function parseLinesDarwin(lines) {
|
||||
let starts = [];
|
||||
let level = -1;
|
||||
let lastlevel = -1;
|
||||
let controllers = [];
|
||||
let displays = [];
|
||||
let currentController = {
|
||||
vendor: '',
|
||||
model: '',
|
||||
bus: '',
|
||||
vram: null,
|
||||
vramDynamic: false
|
||||
function parseLinesDarwin(graphicsArr) {
|
||||
const res = {
|
||||
controllers: [],
|
||||
displays: []
|
||||
};
|
||||
let currentDisplay = {
|
||||
vendor: '',
|
||||
model: '',
|
||||
deviceName: '',
|
||||
main: false,
|
||||
builtin: false,
|
||||
connection: '',
|
||||
sizeX: null,
|
||||
sizeY: null,
|
||||
pixelDepth: null,
|
||||
resolutionX: null,
|
||||
resolutionY: null,
|
||||
currentResX: null,
|
||||
currentResY: null,
|
||||
positionX: 0,
|
||||
positionY: 0,
|
||||
currentRefreshRate: null
|
||||
};
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
if ('' !== lines[i].trim()) {
|
||||
let start = lines[i].search(/\S|$/);
|
||||
if (-1 === starts.indexOf(start)) {
|
||||
starts.push(start);
|
||||
}
|
||||
level = starts.indexOf(start);
|
||||
if (level < lastlevel) {
|
||||
if (Object.keys(currentController).length > 0 && (currentController.vendor || currentController.model)) {// just changed to Displays
|
||||
controllers.push(currentController);
|
||||
currentController = {
|
||||
vendor: '',
|
||||
model: '',
|
||||
bus: '',
|
||||
vram: null,
|
||||
vramDynamic: false
|
||||
};
|
||||
}
|
||||
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
|
||||
if (currentDisplay.resolutionX && currentDisplay.resolutionY) { displays.push(currentDisplay); }
|
||||
currentDisplay = {
|
||||
vendor: '',
|
||||
model: '',
|
||||
deviceName: '',
|
||||
main: false,
|
||||
builtin: false,
|
||||
connection: '',
|
||||
try {
|
||||
graphicsArr.forEach(function (item) {
|
||||
// controllers
|
||||
const bus = ((item.sppci_bus || '').indexOf('builtin') ? 'Built-In' : ((item.sppci_bus || '').indexOf('pcie') ? 'PCIE' : ''));
|
||||
const vram = (parseInt((item._spdisplays_vram || ''), 10) || 0) * (((item._spdisplays_vram || '').indexOf('GB') > -1) ? 1024 : 1);
|
||||
const vramDyn = (parseInt((item.spdisplays_vram_shares || ''), 10) || 0) * (((item.spdisplays_vram_shares || '').indexOf('GB') > -1) ? 1024 : 1);
|
||||
let metalVersion = getMetalVersion(item.spdisplays_metal || item.spdisplays_metalfamily || '');
|
||||
res.controllers.push({
|
||||
vendor: getVendorFromModel(item.spdisplays_vendor || '') || item.spdisplays_vendor || '',
|
||||
model: item.sppci_model || '',
|
||||
bus,
|
||||
vramDynamic: bus === 'Built-In',
|
||||
vram: vram || vramDyn || 0,
|
||||
deviceId: item['spdisplays_device-id'] || '',
|
||||
vendorId: item['spdisplays_vendor-id'] || '',
|
||||
external: (item.sppci_device_type === 'spdisplays_egpu'),
|
||||
cores: item['sppci_cores'] || null,
|
||||
metalVersion
|
||||
});
|
||||
|
||||
// displays
|
||||
if (item.spdisplays_ndrvs && item.spdisplays_ndrvs.length) {
|
||||
item.spdisplays_ndrvs.forEach(function (displayItem) {
|
||||
const connectionType = displayItem['spdisplays_connection_type'];
|
||||
const currentResolutionParts = (displayItem['_spdisplays_resolution'] || '').split('@');
|
||||
const currentResolution = currentResolutionParts[0].split('x');
|
||||
const pixelParts = (displayItem['_spdisplays_pixels'] || '').split('x');
|
||||
const pixelDepthString = displayItem['spdisplays_depth'] || '';
|
||||
const serial = displayItem['_spdisplays_display-serial-number'] || displayItem['_spdisplays_display-serial-number2'] || null;
|
||||
res.displays.push({
|
||||
vendor: getVendorFromId(displayItem['_spdisplays_display-vendor-id'] || '') || getVendorFromModel(displayItem['_name'] || ''),
|
||||
vendorId: displayItem['_spdisplays_display-vendor-id'] || '',
|
||||
model: displayItem['_name'] || '',
|
||||
productionYear: displayItem['_spdisplays_display-year'] || null,
|
||||
serial: serial !== '0' ? serial : null,
|
||||
displayId: displayItem['_spdisplays_displayID'] || null,
|
||||
main: displayItem['spdisplays_main'] ? displayItem['spdisplays_main'] === 'spdisplays_yes' : true,
|
||||
builtin: (displayItem['spdisplays_display_type'] || '').indexOf('built-in') >= 0,
|
||||
connection: ((connectionType.indexOf('_internal')) ? 'Internal' : ((connectionType.indexOf('_displayport')) ? 'Display Port' : ((connectionType.indexOf('_hdmi')) ? 'HDMI' : ''))),
|
||||
sizeX: null,
|
||||
sizeY: null,
|
||||
pixelDepth: null,
|
||||
resolutionX: null,
|
||||
resolutionY: null,
|
||||
currentResX: null,
|
||||
currentResY: null,
|
||||
pixelDepth: (pixelDepthString === 'CGSThirtyBitColor' ? 30 : (pixelDepthString === 'CGSThirtytwoBitColor' ? 32 : (pixelDepthString === 'CGSTwentyfourBitColor' ? 24 : ''))),
|
||||
resolutionX: pixelParts.length > 1 ? parseInt(pixelParts[0], 10) : null,
|
||||
resolutionY: pixelParts.length > 1 ? parseInt(pixelParts[1], 10) : null,
|
||||
currentResX: currentResolution.length > 1 ? parseInt(currentResolution[0], 10) : null,
|
||||
currentResY: currentResolution.length > 1 ? parseInt(currentResolution[1], 10) : null,
|
||||
positionX: 0,
|
||||
positionY: 0,
|
||||
currentRefreshRate: null
|
||||
};
|
||||
}
|
||||
currentRefreshRate: currentResolutionParts.length > 1 ? parseInt(currentResolutionParts[1], 10) : null,
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
lastlevel = level;
|
||||
let parts = lines[i].split(':');
|
||||
if (2 === level) { // grafics controller level
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('chipsetmodel') !== -1) { currentController.model = parts[1].trim(); }
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vendor') !== -1) { currentController.vendor = parts[1].split('(')[0].trim(); }
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(total)') !== -1) {
|
||||
currentController.vram = parseInt(parts[1]); // in MB
|
||||
if (parts[1].toLowerCase().indexOf('gb') !== -1) {
|
||||
currentController.vram = currentController.vram * 1024;
|
||||
}
|
||||
currentController.vramDynamic = false;
|
||||
}
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('vram(dynamic,max)') !== -1) {
|
||||
currentController.vram = parseInt(parts[1]); // in MB
|
||||
if (parts[1].toLowerCase().indexOf('gb') !== -1) {
|
||||
currentController.vram = currentController.vram * 1024;
|
||||
}
|
||||
currentController.vramDynamic = true;
|
||||
}
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('bus') !== -1) {
|
||||
currentController.bus = parts[1].trim();
|
||||
if (currentController.bus.toLowerCase() === 'built-in') {
|
||||
currentController.vramDynamic = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (3 === level) { // display controller level
|
||||
if (parts.length > 1 && '' === parts[1]) {
|
||||
currentDisplay.vendor = getVendorFromModel(parts[0].trim());
|
||||
currentDisplay.model = parts[0].trim();
|
||||
currentDisplay.main = false;
|
||||
currentDisplay.builtin = false;
|
||||
currentDisplay.connection = '';
|
||||
currentDisplay.sizeX = null;
|
||||
currentDisplay.sizeY = null;
|
||||
currentDisplay.positionX = 0;
|
||||
currentDisplay.positionY = 0;
|
||||
currentDisplay.pixelDepth = null;
|
||||
}
|
||||
}
|
||||
if (4 === level) { // display controller details level
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('resolution') !== -1) {
|
||||
let resolution = parts[1].split('x');
|
||||
if (resolution.length > 1) {
|
||||
let xpart = resolution[0];
|
||||
if (xpart.indexOf('(') !== -1) {
|
||||
xpart = xpart.split('(').slice(-1)[0];
|
||||
}
|
||||
let ypart = resolution[1];
|
||||
if (ypart.indexOf(')') !== -1) {
|
||||
ypart = ypart.split(')')[0];
|
||||
}
|
||||
currentDisplay.resolutionX = parseInt(xpart) || 0;
|
||||
currentDisplay.resolutionY = parseInt(ypart) || 0;
|
||||
currentDisplay.currentResX = currentDisplay.resolutionX;
|
||||
currentDisplay.currentResY = currentDisplay.resolutionY;
|
||||
}
|
||||
}
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('pixeldepth') !== -1) { currentDisplay.pixelDepth = parseInt(parts[1]); } // in BIT
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('framebufferdepth') !== -1) { currentDisplay.pixelDepth = parseInt(parts[1]); } // in BIT
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('maindisplay') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') { currentDisplay.main = true; }
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('built-in') !== -1 && parts[1].replace(/ +/g, '').toLowerCase() === 'yes') {
|
||||
currentDisplay.vendor = 'Apple';
|
||||
currentDisplay.builtin = true;
|
||||
currentDisplay.connection = '';
|
||||
}
|
||||
if (parts.length > 1 && parts[0].replace(/ +/g, '').toLowerCase().indexOf('connectiontype') !== -1) {
|
||||
currentDisplay.builtin = false;
|
||||
currentDisplay.connection = parts[1].trim();
|
||||
if (currentDisplay.connection === 'Internal') {
|
||||
currentDisplay.vendor = 'Apple';
|
||||
currentDisplay.builtin = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return res;
|
||||
} catch (e) {
|
||||
return res;
|
||||
}
|
||||
if (Object.keys(currentController).length > 0 && (currentController.vendor || currentController.model)) {// just changed to Displays
|
||||
controllers.push(currentController);
|
||||
}
|
||||
if (Object.keys(currentDisplay).length > 0) {// just changed to Displays
|
||||
if (currentDisplay.resolutionX && currentDisplay.resolutionY) { displays.push(currentDisplay); }
|
||||
}
|
||||
return ({
|
||||
controllers: controllers,
|
||||
displays: displays
|
||||
});
|
||||
}
|
||||
|
||||
function parseLinesLinuxControllers(lines) {
|
||||
@ -706,11 +640,15 @@ function graphics(callback) {
|
||||
displays: []
|
||||
};
|
||||
if (_darwin) {
|
||||
let cmd = 'system_profiler SPDisplaysDataType';
|
||||
let cmd = 'system_profiler -xml -detailLevel full SPDisplaysDataType';
|
||||
exec(cmd, function (error, stdout) {
|
||||
if (!error) {
|
||||
let lines = stdout.toString().split('\n');
|
||||
result = parseLinesDarwin(lines);
|
||||
try {
|
||||
let output = stdout.toString();
|
||||
result = parseLinesDarwin(util.plistParser(output)[0]._items);
|
||||
} catch (e) {
|
||||
util.noop();
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
callback(result);
|
||||
|
||||
89
lib/util.js
89
lib/util.js
@ -985,6 +985,94 @@ function linuxVersion() {
|
||||
return result;
|
||||
}
|
||||
|
||||
function plistParser(xmlStr) {
|
||||
const tags = ['array', 'dict', 'key', 'string', 'integer', 'date', 'real', 'data'];
|
||||
|
||||
function getNextTagPos() {
|
||||
let result = {
|
||||
pos: 999999,
|
||||
tag: ''
|
||||
};
|
||||
tags.forEach((tag) => {
|
||||
const ii = xmlStr.indexOf(`<${tag}>`);
|
||||
if (ii !== -1 && ii < result.pos) {
|
||||
result = {
|
||||
pos: ii,
|
||||
tag
|
||||
};
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function getNextClosingTagPos(tag) {
|
||||
return xmlStr.indexOf(`</${tag}>`);
|
||||
}
|
||||
|
||||
function parseXmlTree(isArray, closingTag) {
|
||||
// start parsing
|
||||
let obj = {};
|
||||
let arr = [];
|
||||
let cpos = getNextTagPos();
|
||||
let key = '';
|
||||
let valueStr = null;
|
||||
|
||||
while (cpos.pos >= 0 && cpos.tag) {
|
||||
let nextTagPos = getNextTagPos();
|
||||
// let nextClosePos = getNextClosingTagPos(cpos.tag);
|
||||
let nextClosePosBlock = closingTag ? getNextClosingTagPos(closingTag) : 999999;
|
||||
if (nextClosePosBlock <= nextTagPos.pos) {
|
||||
return (isArray ? arr : obj);
|
||||
}
|
||||
xmlStr = xmlStr.substring((cpos.pos + cpos.tag.length + 2));
|
||||
if (cpos.tag === 'array') {
|
||||
const res = parseXmlTree(true, cpos.tag);
|
||||
if (key) {
|
||||
obj[key] = res;
|
||||
} else {
|
||||
obj = res;
|
||||
}
|
||||
} else if (cpos.tag === 'dict') {
|
||||
const res = parseXmlTree(false, cpos.tag);
|
||||
if (!isArray) {
|
||||
obj[key] = res;
|
||||
} else {
|
||||
arr.push(res);
|
||||
}
|
||||
xmlStr = xmlStr.substring((cpos.pos + cpos.tag.length + 3));
|
||||
} else {
|
||||
let nextTagPos = getNextTagPos();
|
||||
let nextClosePos = getNextClosingTagPos(cpos.tag);
|
||||
nextClosePosBlock = closingTag ? getNextClosingTagPos(closingTag) : 999999;
|
||||
if (nextClosePos < nextTagPos.pos) {
|
||||
if (cpos.tag === 'key') {
|
||||
key = xmlStr.substring(0, nextClosePos);
|
||||
xmlStr = xmlStr.substring(key.length + cpos.tag.length + 3); // key done
|
||||
} else {
|
||||
valueStr = xmlStr.substring(0, nextClosePos).replace(/\t/g, '');
|
||||
if (cpos.tag === 'string') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
|
||||
if (cpos.tag === 'integer') { if (!isArray) { obj[key] = parseInt(valueStr); } else { arr.push(parseInt(valueStr)); } }
|
||||
if (cpos.tag === 'date') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
|
||||
if (cpos.tag === 'data') { if (!isArray) { obj[key] = valueStr; } else { arr.push(valueStr); } }
|
||||
if (cpos.tag === 'real') { if (!isArray) { obj[key] = parseFloat(valueStr); } else { arr.push(parseFloat(valueStr)); } }
|
||||
|
||||
key = '';
|
||||
xmlStr = xmlStr.substring(valueStr.length + cpos.tag.length + 3); // property done
|
||||
}
|
||||
}
|
||||
}
|
||||
cpos = getNextTagPos();
|
||||
}
|
||||
return (isArray ? arr : obj);
|
||||
}
|
||||
try {
|
||||
const result = parseXmlTree(false, '');
|
||||
return result;
|
||||
} catch (e) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function noop() { }
|
||||
|
||||
exports.toInt = toInt;
|
||||
@ -1020,6 +1108,7 @@ exports.promisify = promisify;
|
||||
exports.promisifySave = promisifySave;
|
||||
exports.smartMonToolsInstalled = smartMonToolsInstalled;
|
||||
exports.linuxVersion = linuxVersion;
|
||||
exports.plistParser = plistParser;
|
||||
exports.stringReplace = stringReplace;
|
||||
exports.stringToLower = stringToLower;
|
||||
exports.stringToString = stringToString;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user