bool TinyGLTF::LoadFromString()

in SpatialInput/External/tiny_gltf.h [2339:2789]


bool TinyGLTF::LoadFromString(Model *model, std::string *err, const char *str,
                              unsigned int length, const std::string &base_dir,
                              unsigned int check_sections) {
    if (length < 4) {
    if (err) {
      (*err) = "JSON string too short.\n";
    }
    return false;
  }

  // TODO(syoyo): Add feature not using exception handling.
  picojson::value v;
  try {
    std::string perr = picojson::parse(v, str, str + length);

    if (!perr.empty()) {
      if (err) {
        (*err) = "JSON parsing error: " + perr;
      }
      return false;
    }
  } catch (std::exception e) {
    if (err) {
      (*err) = e.what();
    }
    return false;
  }

  if (!v.is<picojson::object>()) {
    // root is not an object.
    if (err) {
      (*err) = "Root element is not a JSON object\n";
    }
    return false;
  }

  // scene is not mandatory.
  // FIXME Maybe a better way to handle it than removing the code

  if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
    // OK
  } else if (check_sections & REQUIRE_SCENES) {
    if (err) {
      (*err) += "\"scenes\" object not found in .gltf\n";
    }
    return false;
  }

  if (v.contains("nodes") && v.get("nodes").is<picojson::array>()) {
    // OK
  } else if (check_sections & REQUIRE_NODES) {
    if (err) {
      (*err) += "\"nodes\" object not found in .gltf\n";
    }
    return false;
  }

  if (v.contains("accessors") && v.get("accessors").is<picojson::array>()) {
    // OK
  } else if (check_sections & REQUIRE_ACCESSORS) {
    if (err) {
      (*err) += "\"accessors\" object not found in .gltf\n";
    }
    return false;
  }

  if (v.contains("buffers") && v.get("buffers").is<picojson::array>()) {
    // OK
  } else if (check_sections & REQUIRE_BUFFERS) {
    if (err) {
      (*err) += "\"buffers\" object not found in .gltf\n";
    }
    return false;
  }

  if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
    // OK
  } else if (check_sections & REQUIRE_BUFFER_VIEWS) {
    if (err) {
      (*err) += "\"bufferViews\" object not found in .gltf\n";
    }
    return false;
  }

  model->buffers.clear();
  model->bufferViews.clear();
  model->accessors.clear();
  model->meshes.clear();
  model->cameras.clear();
  model->nodes.clear();
  model->extensionsUsed.clear();
  model->extensionsRequired.clear();
  model->defaultScene = -1;

  // 0. Parse Asset
  if (v.contains("asset") && v.get("asset").is<picojson::object>()) {
    const picojson::object &root = v.get("asset").get<picojson::object>();

    ParseAsset(&model->asset, err, root);
  }

  // 0. Parse extensionUsed
  if (v.contains("extensionsUsed") &&
      v.get("extensionsUsed").is<picojson::array>()) {
    const picojson::array &root =
        v.get("extensionsUsed").get<picojson::array>();
    for (unsigned int i = 0; i < root.size(); ++i) {
      model->extensionsUsed.push_back(root[i].get<std::string>());
    }
  }
  if (v.contains("extensionsRequired") &&
      v.get("extensionsRequired").is<picojson::array>()) {
    const picojson::array &root =
        v.get("extensionsRequired").get<picojson::array>();
    for (unsigned int i = 0; i < root.size(); ++i) {
      model->extensionsRequired.push_back(root[i].get<std::string>());
    }
  }

  // 1. Parse Buffer
  if (v.contains("buffers") && v.get("buffers").is<picojson::array>()) {
    const picojson::array &root = v.get("buffers").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`buffers' does not contain an JSON object.";
        }
        return false;
      }
      Buffer buffer;
      if (!ParseBuffer(&buffer, err, it->get<picojson::object>(), base_dir,
                       is_binary_, bin_data_, bin_size_)) {
        return false;
      }

      model->buffers.push_back(buffer);
    }
  }

  // 2. Parse BufferView
  if (v.contains("bufferViews") && v.get("bufferViews").is<picojson::array>()) {
    const picojson::array &root = v.get("bufferViews").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`bufferViews' does not contain an JSON object.";
        }
        return false;
      }
      BufferView bufferView;
      if (!ParseBufferView(&bufferView, err, it->get<picojson::object>())) {
        return false;
      }

      model->bufferViews.push_back(bufferView);
    }
  }

  // 3. Parse Accessor
  if (v.contains("accessors") && v.get("accessors").is<picojson::array>()) {
    const picojson::array &root = v.get("accessors").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`accessors' does not contain an JSON object.";
        }
        return false;
      }
      Accessor accessor;
      if (!ParseAccessor(&accessor, err, it->get<picojson::object>())) {
        return false;
      }

      model->accessors.push_back(accessor);
    }
  }

  // 4. Parse Mesh
  if (v.contains("meshes") && v.get("meshes").is<picojson::array>()) {
    const picojson::array &root = v.get("meshes").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`meshes' does not contain an JSON object.";
        }
        return false;
      }
      Mesh mesh;
      if (!ParseMesh(&mesh, err, it->get<picojson::object>())) {
        return false;
      }

      model->meshes.push_back(mesh);
    }
  }

  // 5. Parse Node
  if (v.contains("nodes") && v.get("nodes").is<picojson::array>()) {
    const picojson::array &root = v.get("nodes").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`nodes' does not contain an JSON object.";
        }
        return false;
      }
      Node node;
      if (!ParseNode(&node, err, it->get<picojson::object>())) {
        return false;
      }

      model->nodes.push_back(node);
    }
  }

  // 6. Parse scenes.
  if (v.contains("scenes") && v.get("scenes").is<picojson::array>()) {
    const picojson::array &root = v.get("scenes").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!(it->is<picojson::object>())) {
        if (err) {
          (*err) += "`scenes' does not contain an JSON object.";
        }
        return false;
      }
      const picojson::object &o = it->get<picojson::object>();
      std::vector<double> nodes;
      if (!ParseNumberArrayProperty(&nodes, err, o, "nodes", false)) {
        return false;
      }

      Scene scene;
      ParseStringProperty(&scene.name, err, o, "name", false);
      std::vector<int> nodesIds;
      for (size_t i = 0; i < nodes.size(); i++) {
        nodesIds.push_back(static_cast<int>(nodes[i]));
      }
      scene.nodes = nodesIds;

      model->scenes.push_back(scene);
    }
  }

  // 7. Parse default scenes.
  if (v.contains("scene") && v.get("scene").is<double>()) {
    const int defaultScene = int(v.get("scene").get<double>());

    model->defaultScene = static_cast<int>(defaultScene);
  }

  // 8. Parse Material
  if (v.contains("materials") && v.get("materials").is<picojson::array>()) {
    const picojson::array &root = v.get("materials").get<picojson::array>();
    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`materials' does not contain an JSON object.";
        }
        return false;
      }
      picojson::object jsonMaterial = it->get<picojson::object>();

      Material material;
      ParseStringProperty(&material.name, err, jsonMaterial, "name", false);

      if (!ParseMaterial(&material, err, jsonMaterial)) {
        return false;
      }

      model->materials.push_back(material);
    }
  }

  // 9. Parse Image
  if (v.contains("images") && v.get("images").is<picojson::array>()) {
    const picojson::array &root = v.get("images").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`images' does not contain an JSON object.";
        }
        return false;
      }
      Image image;
      if (!ParseImage(&image, err, it->get<picojson::object>(), base_dir,
                      is_binary_, bin_data_, bin_size_)) {
        return false;
      }

      if (image.bufferView != -1) {
        // Load image from the buffer view.
        if (size_t(image.bufferView) >= model->bufferViews.size()) {
          if (err) {
            std::stringstream ss;
            ss << "bufferView \"" << image.bufferView
               << "\" not found in the scene." << std::endl;
            (*err) += ss.str();
          }
          return false;
        }

        const BufferView &bufferView =
            model->bufferViews[size_t(image.bufferView)];
        const Buffer &buffer = model->buffers[size_t(bufferView.buffer)];

        bool ret = LoadImageData(&image, err, image.width, image.height,
                                 &buffer.data[bufferView.byteOffset],
                                 static_cast<int>(bufferView.byteLength));
        if (!ret) {
          return false;
        }
      }

      model->images.push_back(image);
    }
  }

  // 10. Parse Texture
  if (v.contains("textures") && v.get("textures").is<picojson::array>()) {
    const picojson::array &root = v.get("textures").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; it++) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`textures' does not contain an JSON object.";
        }
        return false;
      }
      Texture texture;
      if (!ParseTexture(&texture, err, it->get<picojson::object>(), base_dir)) {
        return false;
      }

      model->textures.push_back(texture);
    }
  }

  // 11. Parse Animation
  if (v.contains("animations") && v.get("animations").is<picojson::array>()) {
    const picojson::array &root = v.get("animations").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; ++it) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`animations' does not contain an JSON object.";
        }
        return false;
      }
      Animation animation;
      if (!ParseAnimation(&animation, err, it->get<picojson::object>())) {
        return false;
      }

      model->animations.push_back(animation);
    }
  }

  // 12. Parse Skin
  if (v.contains("skins") && v.get("skins").is<picojson::array>()) {
    const picojson::array &root = v.get("skins").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; ++it) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`skins' does not contain an JSON object.";
        }
        return false;
      }
      Skin skin;
      if (!ParseSkin(&skin, err, it->get<picojson::object>())) {
        return false;
      }

      model->skins.push_back(skin);
    }
  }

  // 13. Parse Sampler
  if (v.contains("samplers") && v.get("samplers").is<picojson::array>()) {
    const picojson::array &root = v.get("samplers").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; ++it) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`samplers' does not contain an JSON object.";
        }
        return false;
      }
      Sampler sampler;
      if (!ParseSampler(&sampler, err, it->get<picojson::object>())) {
        return false;
      }

      model->samplers.push_back(sampler);
    }
  }

  // 14. Parse Camera
  if (v.contains("cameras") && v.get("cameras").is<picojson::array>()) {
    const picojson::array &root = v.get("cameras").get<picojson::array>();

    picojson::array::const_iterator it(root.begin());
    picojson::array::const_iterator itEnd(root.end());
    for (; it != itEnd; ++it) {
      if (!it->is<picojson::object>()) {
        if (err) {
          (*err) += "`cameras' does not contain an JSON object.";
        }
        return false;
      }
      Camera camera;
      if (!ParseCamera(&camera, err, it->get<picojson::object>())) {
        return false;
      }

      model->cameras.push_back(camera);
    }
  }
  return true;
}