| 158 | } |
| 159 | |
| 160 | MjModelPtr LoadModelFromString(std::string_view xml, char* error, |
| 161 | int error_size, mjVFS* vfs) { |
| 162 | if (error) { |
| 163 | error[0] = '\0'; |
| 164 | } |
| 165 | |
| 166 | // This duplicates the logic in mj_loadXML, but allows us to use a string |
| 167 | // directly rather than having to write the contents to a file. Most |
| 168 | // importantly, we "save" the spec to global storage so that subsequent calls |
| 169 | // to mj_saveLastXML will be done using the parsed mjSpec. |
| 170 | mjSpec* spec = mj_parseXMLString(xml.data(), vfs, error, error_size); |
| 171 | |
| 172 | mjModel* model = nullptr; |
| 173 | if (spec) { |
| 174 | model = mj_compile(spec, vfs); |
| 175 | |
| 176 | if (error) { |
| 177 | if (!model) { |
| 178 | strncpy(error, mjs_getError(spec), error_size); |
| 179 | error[error_size - 1] = '\0'; |
| 180 | } else { |
| 181 | int num_warnings = mjs_numWarnings(spec); |
| 182 | if (num_warnings > 0) { |
| 183 | std::string all_warnings; |
| 184 | for (int i = 0; i < num_warnings; ++i) { |
| 185 | if (!all_warnings.empty()) { |
| 186 | all_warnings += '\n'; |
| 187 | } |
| 188 | all_warnings += mjs_getWarning(spec, i); |
| 189 | } |
| 190 | strncpy(error, all_warnings.c_str(), error_size); |
| 191 | error[error_size - 1] = '\0'; |
| 192 | } else { |
| 193 | error[0] = '\0'; |
| 194 | } |
| 195 | } |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | SetGlobalXmlSpec(spec); |
| 200 | return MjModelPtr(model); |
| 201 | } |
| 202 | |
| 203 | MjDataPtr MakeData(const MjModelPtr& model) { |
| 204 | return MjDataPtr(mj_makeData(model.get())); |