* Save or Load a table header. * @note a table-header can never contain more than 65535 fields. * @param slt The SaveLoad table with objects to save/load. * @return When loading, the ordered SaveLoad array to use; otherwise an empty list. */
| 1897 | * @return When loading, the ordered SaveLoad array to use; otherwise an empty list. |
| 1898 | */ |
| 1899 | std::vector<SaveLoad> SlTableHeader(const SaveLoadTable &slt) |
| 1900 | { |
| 1901 | /* You can only use SlTableHeader if you are a CH_TABLE. */ |
| 1902 | assert(_sl.block_mode == CH_TABLE || _sl.block_mode == CH_SPARSE_TABLE); |
| 1903 | |
| 1904 | switch (_sl.action) { |
| 1905 | case SLA_LOAD_CHECK: |
| 1906 | case SLA_LOAD: { |
| 1907 | std::vector<SaveLoad> saveloads; |
| 1908 | |
| 1909 | /* Build a key lookup mapping based on the available fields. */ |
| 1910 | std::map<std::string, const SaveLoad *> key_lookup; |
| 1911 | for (auto &sld : slt) { |
| 1912 | if (!SlIsObjectValidInSavegame(sld)) continue; |
| 1913 | |
| 1914 | /* Check that there is only one active SaveLoad for a given name. */ |
| 1915 | assert(key_lookup.find(sld.name) == key_lookup.end()); |
| 1916 | key_lookup[sld.name] = &sld; |
| 1917 | } |
| 1918 | |
| 1919 | while (true) { |
| 1920 | uint8_t type = 0; |
| 1921 | SlSaveLoadConv(&type, SLE_UINT8); |
| 1922 | if (type == SLE_FILE_END) break; |
| 1923 | |
| 1924 | std::string key; |
| 1925 | SlStdString(&key, SLE_STR); |
| 1926 | |
| 1927 | auto sld_it = key_lookup.find(key); |
| 1928 | if (sld_it == key_lookup.end()) { |
| 1929 | /* SLA_LOADCHECK triggers this debug statement a lot and is perfectly normal. */ |
| 1930 | Debug(sl, _sl.action == SLA_LOAD ? 2 : 6, "Field '{}' of type 0x{:02x} not found, skipping", key, type); |
| 1931 | |
| 1932 | std::shared_ptr<SaveLoadHandler> handler = nullptr; |
| 1933 | SaveLoadType saveload_type; |
| 1934 | switch (type & SLE_FILE_TYPE_MASK) { |
| 1935 | case SLE_FILE_STRING: |
| 1936 | /* Strings are always marked with SLE_FILE_HAS_LENGTH_FIELD, as they are a list of chars. */ |
| 1937 | saveload_type = SL_STDSTR; |
| 1938 | break; |
| 1939 | |
| 1940 | case SLE_FILE_STRUCT: |
| 1941 | /* Structs are always marked with SLE_FILE_HAS_LENGTH_FIELD as SL_STRUCT is seen as a list of 0/1 in length. */ |
| 1942 | saveload_type = SL_STRUCTLIST; |
| 1943 | handler = std::make_shared<SlSkipHandler>(); |
| 1944 | break; |
| 1945 | |
| 1946 | default: |
| 1947 | saveload_type = (type & SLE_FILE_HAS_LENGTH_FIELD) ? SL_ARR : SL_VAR; |
| 1948 | break; |
| 1949 | } |
| 1950 | |
| 1951 | /* We don't know this field, so read to nothing. */ |
| 1952 | saveloads.emplace_back(std::move(key), saveload_type, ((VarType)type & SLE_FILE_TYPE_MASK) | SLE_VAR_NULL, 1, SL_MIN_VERSION, SL_MAX_VERSION, nullptr, 0, std::move(handler)); |
| 1953 | continue; |
| 1954 | } |
| 1955 | |
| 1956 | /* Validate the type of the field. If it is changed, the |
no test coverage detected