156 lines
6.7 KiB
C++
156 lines
6.7 KiB
C++
/*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "Base/Logger.hpp"
|
|
#include "Data/Containers/String.hpp"
|
|
#include <fmt/format.h>
|
|
#include <c4/format.hpp>
|
|
#include <map>
|
|
|
|
namespace OpenVulkano
|
|
{
|
|
namespace
|
|
{
|
|
std::tuple<std::string_view, int, int> SplitAppleModelComponents(std::string_view input)
|
|
{
|
|
size_t commaPos = input.rfind(',');
|
|
|
|
// Find the boundary between text and number
|
|
size_t numberStart = commaPos - 1;
|
|
while (numberStart > 0 && std::isdigit(input[numberStart - 1])) { --numberStart; }
|
|
|
|
if (numberStart < 1 || commaPos == std::string_view::npos) return { input, -1, -1 };
|
|
|
|
std::string_view beforeNumber = input.substr(0, numberStart);
|
|
std::string_view number = input.substr(numberStart, commaPos - numberStart);
|
|
std::string_view afterComma = input.substr(commaPos + 1);
|
|
|
|
int major = -1, minor = -1;
|
|
c4::from_chars(c4::csubstr(number.begin(), number.length()), &major);
|
|
c4::from_chars(c4::csubstr(afterComma.begin(), afterComma.length()), &minor);
|
|
|
|
return { beforeNumber, major, minor };
|
|
}
|
|
|
|
std::string DecodeIPhoneName(int major, int minor)
|
|
{
|
|
uint32_t number = std::max(major - 1, 1);
|
|
std::string suffix;
|
|
switch(major)
|
|
{
|
|
case 1: if (minor == 1) number = 1; else if (minor == 2) { number = 3; suffix = "G"; } break;
|
|
case 2: number = 3; suffix = "GS";
|
|
case 4: suffix = "s"; //fallthrough
|
|
case 3: number = 4; break;
|
|
case 6: suffix = "s"; //fallthrough
|
|
case 5: number = 5; if(minor > 2) suffix = "c"; break;
|
|
case 7: if (minor == 1) suffix = " Plus"; break;
|
|
case 8: if (minor == 4) return "iPhone SE";
|
|
number = 6; suffix = "s";
|
|
if (minor == 2) suffix += " Plus"; break;
|
|
case 9: number = 7; if ((minor & 1) == 0) suffix = " Plus"; break;
|
|
case 10: if (minor < 3) { number = 8; if (minor == 2) suffix = " Plus"; } else return "iPhone X"; break;
|
|
case 11: { switch (minor) {
|
|
case 2: return "iPhone XS";
|
|
case 8: return "iPhone XR";
|
|
case 4: case 6: return "iPhone XS Max";
|
|
} break; }
|
|
case 12:
|
|
if (minor == 8) return "iPhone SE (2nd generation)";
|
|
if (minor > 2) suffix = " Pro"; if (minor > 4) suffix += " Max"; break;
|
|
case 13:
|
|
if (minor == 1) { suffix = " Mini"; break; }
|
|
if (minor > 2) suffix = " Pro"; if (minor == 4) suffix += " Max"; break;
|
|
case 14: if (minor == 6) return "iPhone SE (3nd generation)";
|
|
if (minor == 2) suffix = " Pro"; if (minor == 3) suffix = " Pro Max";
|
|
if (minor == 4) suffix = " Mini"; if (minor > 6) number = 14; if (minor == 8) suffix = " Plus";
|
|
break;
|
|
case 15:
|
|
if (minor == 2) suffix = " Pro"; else if (minor == 3) suffix = " Pro Max";
|
|
else if (minor > 3) number = 15; if (minor == 5) suffix = " Plus"; break;
|
|
case 16: suffix = " Pro"; if (minor == 2) suffix += " Max"; break;
|
|
case 17: if (minor == 1) suffix = " Pro"; else if (minor == 2) suffix = " Pro Max"; else if (minor == 4) suffix = " Plus"; else if (minor == 5) suffix = "e"; break;
|
|
case 18: if (minor == 1) suffix = " Pro"; else if (minor == 2) suffix = " Pro Max"; else if (minor == 4) return "iPhone Air";
|
|
}
|
|
return fmt::format("iPhone {}{}", number, suffix);
|
|
}
|
|
|
|
std::string DecodeIPadName(int major, int minor)
|
|
{
|
|
std::string type = "unknown";
|
|
uint32_t gen = major * 1000 + minor;
|
|
std::map<std::pair<int, int>, std::pair<std::string, uint32_t>> options = {
|
|
{{1, 1}, {"", 1}}, {{1, 2}, {"", 1}}, {{1, 3}, {"", 1}},
|
|
{{2, 1}, {"", 2}}, {{2, 2}, {"", 2}}, {{2, 3}, {"", 2}}, {{2, 4}, {"", 2}},
|
|
{{3, 1}, {"", 3}}, {{3, 2}, {"", 3}}, {{3, 3}, {"", 3}},
|
|
{{3, 4}, {"", 4}}, {{3, 5}, {"", 4}}, {{3, 6}, {"", 4}},
|
|
{{6, 11}, {"", 5}}, {{6, 12}, {"", 5}},
|
|
{{7, 5}, {"", 6}}, {{7, 6}, {"", 6}},
|
|
{{7, 11}, {"", 7}}, {{7, 12}, {"", 7}},
|
|
{{11, 6}, {"", 8}}, {{11, 7}, {"", 8}},
|
|
{{12, 1}, {"", 9}}, {{12, 2}, {"", 9}},
|
|
{{13, 18}, {"", 10}}, {{13, 19}, {"", 10}},
|
|
{{2, 5}, {"Mini", 1}}, {{2, 6}, {"Mini", 1}}, {{2, 7}, {"Mini", 1}},
|
|
{{4, 4}, {"Mini", 2}}, {{4, 5}, {"Mini", 2}}, {{4, 6}, {"Mini", 2}},
|
|
{{4, 7}, {"Mini", 3}}, {{4, 8}, {"Mini", 3}}, {{4, 9}, {"Mini", 3}},
|
|
{{5, 1}, {"Mini", 4}}, {{5, 2}, {"Mini", 4}},
|
|
{{11, 1}, {"Mini", 5}}, {{11, 2}, {"Mini", 5}},
|
|
{{14, 1}, {"Mini", 6}}, {{14, 2}, {"Mini", 6}},
|
|
{{4, 1}, {"Air", 1}}, {{4, 2}, {"Air", 1}}, {{4, 3}, {"Air", 1}},
|
|
{{5, 3}, {"Air", 2}}, {{5, 4}, {"Air", 2}},
|
|
{{11, 3}, {"Air", 3}}, {{11, 4}, {"Air", 3}},
|
|
{{13, 1}, {"Air", 4}}, {{13, 2}, {"Air", 4}},
|
|
{{13, 16}, {"Air", 5}}, {{13, 17}, {"Air", 5}},
|
|
{{6, 7}, {"Pro 12.9\"", 1}}, {{6, 8}, {"Pro 12.9\"", 1}},
|
|
{{7, 1}, {"Pro 12.9\"", 2}}, {{7, 2}, {"Pro 12.9\"", 2}},
|
|
{{8, 5}, {"Pro 12.9\"", 3}}, {{8, 6}, {"Pro 12.9\"", 3}}, {{8, 7}, {"Pro 12.9\"", 3}}, {{8, 8}, {"Pro 12.9\"", 3}},
|
|
{{8, 11}, {"Pro 12.9\"", 4}}, {{8, 12}, {"Pro 12.9\"", 4}},
|
|
{{13, 8}, {"Pro 12.9\"", 5}}, {{13, 9}, {"Pro 12.9\"", 5}}, {{13, 10}, {"Pro 12.9\"", 5}}, {{13, 11}, {"Pro 12.9\"", 5}},
|
|
{{14, 5}, {"Pro 12.9\"", 6}}, {{14, 6}, {"Pro 12.9\"", 6}},
|
|
{{16, 5}, {"Pro 12.9\"", 7}}, {{16, 6}, {"Pro 12.9\"", 7}},
|
|
{{6, 3}, {"Pro 9.7\"", 1}}, {{6, 4}, {"Pro 9.7\"", 1}},
|
|
{{7, 3}, {"Pro 10.5\"", 1}}, {{7, 4}, {"Pro 10.5\"", 1}},
|
|
{{8, 1}, {"Pro 11\"", 1}}, {{8, 2}, {"Pro 11\"", 1}}, {{8, 3}, {"Pro 11\"", 1}}, {{8, 4}, {"Pro 11\"", 1}},
|
|
{{8, 9}, {"Pro 11\"", 2}}, {{8, 10}, {"Pro 11\"", 2}},
|
|
{{13, 4}, {"Pro 11\"", 3}}, {{13, 5}, {"Pro 11\"", 3}}, {{13, 6}, {"Pro 11\"", 3}}, {{13, 7}, {"Pro 11\"", 3}},
|
|
{{14, 3}, {"Pro 11\"", 4}}, {{14, 4}, {"Pro 11\"", 4}},
|
|
{{16, 3}, {"Pro 11\"", 5}}, {{16, 4}, {"Pro 11\"", 5}},
|
|
};
|
|
auto iter = options.find({major, minor});
|
|
if (iter != options.end())
|
|
{
|
|
type = iter->second.first;
|
|
gen = iter->second.second;
|
|
}
|
|
else
|
|
{
|
|
spdlog::warn("Could not decode iPad identifier iPad{},{}", major, minor);
|
|
}
|
|
return fmt::format("iPad {} ({}{} generation)", type, gen, String::GetOrdinal(gen));
|
|
}
|
|
|
|
std::string DecodeModelString(const std::string& model)
|
|
{
|
|
if (model == "i386" || model == "x86_64") return "Simulator";
|
|
auto [type, major, minor] = SplitAppleModelComponents(model);
|
|
if (type == "iPhone") return DecodeIPhoneName(major, minor);
|
|
else if (type == "iPad") return DecodeIPadName(major, minor);
|
|
else if (type == "iPod")
|
|
{
|
|
if (major == 7) major = 6; else if (major == 9) major = 7;
|
|
return fmt::format("iPod touch ({}{} generation)", major, String::GetOrdinal(major));
|
|
}
|
|
else
|
|
{
|
|
spdlog::warn("Could not decode identifier {}", model);
|
|
}
|
|
return "";
|
|
}
|
|
}
|
|
}
|