(Scene3D) Use File API rather than std file loading methods 68/312368/5
authorAdeel Kazmi <adeel.kazmi@samsung.com>
Fri, 7 Jun 2024 13:09:20 +0000 (14:09 +0100)
committerAdeel Kazmi <adeel.kazmi@samsung.com>
Wed, 3 Jul 2024 15:54:08 +0000 (15:54 +0000)
Change-Id: Ia2f323bcc908cb51728159c8695fcae7ca5a8bc2

automated-tests/resources/headerOK-invalidArray.ktx [new file with mode: 0644]
automated-tests/resources/headerOnly.ktx [new file with mode: 0644]
automated-tests/src/dali-scene3d/utc-Dali-KtxLoader.cpp
automated-tests/src/dali-scene3d/utc-Dali-MeshDefinition.cpp
dali-scene3d/public-api/loader/ktx-loader.cpp
dali-scene3d/public-api/loader/mesh-definition.cpp
dali-scene3d/public-api/loader/utils.cpp

diff --git a/automated-tests/resources/headerOK-invalidArray.ktx b/automated-tests/resources/headerOK-invalidArray.ktx
new file mode 100644 (file)
index 0000000..d65cb30
Binary files /dev/null and b/automated-tests/resources/headerOK-invalidArray.ktx differ
diff --git a/automated-tests/resources/headerOnly.ktx b/automated-tests/resources/headerOnly.ktx
new file mode 100644 (file)
index 0000000..6c1e998
Binary files /dev/null and b/automated-tests/resources/headerOnly.ktx differ
index 18b9d084cefcc0fe2d94119e63c261f3e943f14d..4accb91671028a5b6557ab35b183a4cacb19fe09 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,6 +55,20 @@ int UtcDaliKtxLoaderFailTruncated(void)
   END_TEST;
 }
 
+int UtcDaliKtxLoaderFailValidHeaderInvalidArray(void)
+{
+  EnvironmentMapData environmentMapData;
+  DALI_TEST_CHECK(!LoadKtxData(TEST_RESOURCE_DIR "/headerOK-invalidArray.ktx", environmentMapData));
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderFailValidHeaderOnly(void)
+{
+  EnvironmentMapData environmentMapData;
+  DALI_TEST_CHECK(!LoadKtxData(TEST_RESOURCE_DIR "/headerOnly.ktx", environmentMapData));
+  END_TEST;
+}
+
 int UtcDaliKtxLoaderSuccess(void)
 {
   EnvironmentMapData environmentMapData;
index ba67d42378ddb813b1fe83ba740c298e9fa1b0ff..2754ad3a2640fb95392dc04c43a99d76aba02749 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -173,3 +173,13 @@ int UtcDaliMeshDefinitionShortSkinWeight(void)
   }
   END_TEST;
 }
+
+int UtcDaliMeshDefinitionInvalidUrl(void)
+{
+  MeshDefinition meshDefinition;
+  meshDefinition.mUri = "invalid-uri/";
+  BufferDefinition::Vector buffers;
+  MeshDefinition::RawData rawData = meshDefinition.LoadRaw("invalidModelPath", buffers);
+  DALI_TEST_EQUALS(rawData.mIndices.size(), 0u, TEST_LOCATION);
+  END_TEST;
+}
\ No newline at end of file
index 4d33ef5d8499baab26dbcdc4492db35024651c56..149a2c3f1a5e93e3fe54c6df73baba87f7b395d9 100644 (file)
 #include <dali-scene3d/public-api/loader/ktx-loader.h>
 
 // EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
 #include <dali/integration-api/pixel-data-integ.h>
 #include <dali/public-api/rendering/texture.h>
+#include <dali/devel-api/adaptor-framework/file-stream.h>
 #include <fstream>
 #include <memory>
 
@@ -188,26 +190,33 @@ bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Pixel::Format& format)
 
 bool LoadKtxData(const std::string& path, EnvironmentMapData& environmentMapData)
 {
-  std::fstream fp(path, std::ios::in | std::ios::binary);
-  if(fp.is_open() == false)
+  Dali::FileStream fileStream(path, FileStream::READ | FileStream::BINARY);
+  auto&            stream = fileStream.GetStream();
+  if(!stream.good() || !stream.rdbuf()->in_avail())
   {
+    DALI_LOG_ERROR("Load ktx data failed, path : %s\n", path.c_str());
     return false;
   }
 
   KtxFileHeader header;
-  if(fp.read(reinterpret_cast<char*>(&header), sizeof(KtxFileHeader)).good() == false)
+  stream.clear();
+  stream.seekg(0u, stream.beg);
+  if(stream.read(reinterpret_cast<char*>(&header), sizeof(KtxFileHeader)).good() == false)
   {
+    DALI_LOG_ERROR("Unable to read ktx header in file, %s\n", path.c_str());
     return false;
   }
 
   if(!header.IsIdentifierValid())
   {
+    DALI_LOG_ERROR("KTX Header Identifier is not valid, %s\n", path.c_str());
     return false;
   }
 
   // Skip the key-values:
-  if(fp.seekg(static_cast<std::streamoff>(static_cast<std::size_t>(header.bytesOfKeyValueData)), fp.cur).good() == false)
+  if(stream.seekg(static_cast<std::streamoff>(static_cast<std::size_t>(header.bytesOfKeyValueData)), stream.cur).good() == false)
   {
+    DALI_LOG_ERROR("Unable to skip key-values in KTX file, %s\n", path.c_str());
     return false;
   }
 
@@ -230,8 +239,9 @@ bool LoadKtxData(const std::string& path, EnvironmentMapData& environmentMapData
   for(uint32_t mipmapLevel = 0u; mipmapLevel < header.numberOfMipmapLevels; ++mipmapLevel)
   {
     uint32_t byteSize = 0u;
-    if(fp.read(reinterpret_cast<char*>(&byteSize), sizeof(byteSize)).good() == false)
+    if(stream.read(reinterpret_cast<char*>(&byteSize), sizeof(byteSize)).good() == false)
     {
+      DALI_LOG_ERROR("Unable to read byteSize from KTX stream, %s\n", path.c_str());
       return false;
     }
 
@@ -245,8 +255,9 @@ bool LoadKtxData(const std::string& path, EnvironmentMapData& environmentMapData
       for(uint32_t face = 0u; face < header.numberOfFaces; ++face)
       {
         std::unique_ptr<uint8_t, void (*)(uint8_t*)> img(new uint8_t[byteSize], FreeBuffer);
-        if(fp.read(reinterpret_cast<char*>(img.get()), static_cast<std::streamsize>(static_cast<size_t>(byteSize))).good() == false)
+        if(stream.read(reinterpret_cast<char*>(img.get()), static_cast<std::streamsize>(static_cast<size_t>(byteSize))).good() == false)
         {
+          DALI_LOG_ERROR("Unable to read data from KTX stream, %s\n", path.c_str());
           return false;
         }
         environmentMapData.mPixelData[face][mipmapLevel] = Dali::Integration::NewPixelDataWithReleaseAfterUpload(img.release(), byteSize, header.pixelWidth, header.pixelHeight, 0u, daliformat, PixelData::DELETE_ARRAY);
index 67287903a12cfb963bf100530e866e4780e30db8..a417fd0e996e163f4bbf36da7d28ea6cb869055d 100644 (file)
@@ -44,7 +44,7 @@ struct LoadAccessorInputs
   MeshDefinition::RawData&  rawData;
   MeshDefinition::Accessor& accessor;
   uint32_t                  flags;
-  std::fstream&             fileStream;
+  std::iostream*            fileStream;
   std::string&              meshPath;
   BufferDefinition::Vector& buffers;
 };
@@ -54,7 +54,7 @@ struct LoadAccessorListInputs
   MeshDefinition::RawData&               rawData;
   std::vector<MeshDefinition::Accessor>& accessors;
   uint32_t                               flags;
-  std::fstream&                          fileStream;
+  std::iostream*                         fileStream;
   std::string&                           meshPath;
   BufferDefinition::Vector&              buffers;
 };
@@ -816,10 +816,10 @@ void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::vector<MeshDefiniti
   }
 }
 
-std::iostream& GetAvailableData(std::fstream& meshStream, const std::string& meshPath, BufferDefinition& buffer, std::string& availablePath)
+std::iostream& GetAvailableData(std::iostream* meshStream, const std::string& meshPath, BufferDefinition& buffer, std::string& availablePath)
 {
-  auto& stream  = (meshStream.is_open()) ? meshStream : buffer.GetBufferStream();
-  availablePath = (meshStream.is_open()) ? meshPath : buffer.GetUri();
+  auto& stream  = meshStream ? *meshStream : buffer.GetBufferStream();
+  availablePath = meshStream ? meshPath : buffer.GetUri();
   return stream;
 }
 
@@ -855,6 +855,7 @@ void LoadIndices(LoadAccessorInputs indicesInput)
       auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
       if(!ReadAccessor(indicesInput.accessor, stream, reinterpret_cast<uint8_t*>(indicesInput.rawData.mIndices.data())))
       {
+        DALI_LOG_ERROR("Failed to read indices from %s\n", path.c_str());
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
       }
     }
@@ -871,6 +872,7 @@ void LoadIndices(LoadAccessorInputs indicesInput)
       auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
       if(!ReadAccessor(indicesInput.accessor, stream, u8s))
       {
+        DALI_LOG_ERROR("Failed to read indices from %s\n", path.c_str());
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
       }
 
@@ -894,6 +896,7 @@ void LoadIndices(LoadAccessorInputs indicesInput)
       auto&       stream = GetAvailableData(indicesInput.fileStream, indicesInput.meshPath, indicesInput.buffers[indicesInput.accessor.mBufferIdx], path);
       if(!ReadAccessor(indicesInput.accessor, stream, reinterpret_cast<uint8_t*>(indicesInput.rawData.mIndices.data())))
       {
+        DALI_LOG_ERROR("Failed to read indices from %s\n", path.c_str());
         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indicesInput.accessor from '" << path << "'.";
       }
     }
@@ -1211,7 +1214,7 @@ void LoadColors(LoadAccessorListInputs colorsInput)
       colorsInput.rawData.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
     }
   }
-  else
+  else if(!colorsInput.rawData.mAttribs.empty())
   {
     std::vector<uint8_t> buffer(colorsInput.rawData.mAttribs[0].mNumElements * sizeof(Vector4));
     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
@@ -1225,7 +1228,7 @@ void LoadColors(LoadAccessorListInputs colorsInput)
   }
 }
 
-void LoadBlendShapes(MeshDefinition::RawData& rawData, std::vector<MeshDefinition::BlendShape>& blendShapes, MeshDefinition::Blob& blendShapeHeader, BlendShapes::Version blendShapeVersion, uint32_t numberOfVertices, std::fstream& fileStream, BufferDefinition::Vector& buffers)
+void LoadBlendShapes(MeshDefinition::RawData& rawData, std::vector<MeshDefinition::BlendShape>& blendShapes, MeshDefinition::Blob& blendShapeHeader, BlendShapes::Version blendShapeVersion, uint32_t numberOfVertices, std::istream* fileStream, BufferDefinition::Vector& buffers)
 {
   // Calculate the Blob for the blend shapes.
   MeshDefinition::Blob blendShapesBlob;
@@ -1269,10 +1272,10 @@ void LoadBlendShapes(MeshDefinition::RawData& rawData, std::vector<MeshDefinitio
       CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
       calculateGltf2BlendShapes = true;
     }
-    else
+    else if(fileStream)
     {
       uint16_t header[2u];
-      ReadBlob(blendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
+      ReadBlob(blendShapeHeader, *fileStream, reinterpret_cast<uint8_t*>(header));
       textureWidth  = header[0u];
       textureHeight = header[1u];
     }
@@ -1294,16 +1297,16 @@ void LoadBlendShapes(MeshDefinition::RawData& rawData, std::vector<MeshDefinitio
 
       if(blendShapesBlob.IsDefined())
       {
-        if(ReadBlob(blendShapesBlob, fileStream, geometryBuffer))
+        if(fileStream && ReadBlob(blendShapesBlob, *fileStream, geometryBuffer))
         {
           unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
         }
       }
 
       // Read the unnormalize factors.
-      if(unnormalizeFactorBlob.IsDefined())
+      if(unnormalizeFactorBlob.IsDefined() && fileStream)
       {
-        ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&rawData.mBlendShapeUnnormalizeFactor[0u]));
+        ReadBlob(unnormalizeFactorBlob, *fileStream, reinterpret_cast<uint8_t*>(&rawData.mBlendShapeUnnormalizeFactor[0u]));
       }
     }
     rawData.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
@@ -1473,20 +1476,24 @@ MeshDefinition::RawData
 MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
 {
   RawData raw;
-  if(IsQuad())
+  if (IsQuad())
   {
     return raw;
   }
 
   std::string meshPath;
   meshPath = modelsPath + mUri;
-  std::fstream fileStream;
-  if(!mUri.empty())
+
+  std::unique_ptr<Dali::FileStream> daliFileStream(nullptr);
+  std::iostream* fileStream = nullptr;
+  if (!mUri.empty())
   {
-    fileStream.open(meshPath, std::ios::in | std::ios::binary);
-    if(!fileStream.is_open())
+    daliFileStream.reset(new Dali::FileStream(meshPath, FileStream::READ | FileStream::BINARY));
+    fileStream = &daliFileStream->GetStream();
+    if(!fileStream->good() || !fileStream->rdbuf()->in_avail())
     {
       DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
+      fileStream = nullptr;
     }
   }
 
index 9120b65a687b326cfe8dbbdd08816373ac72683e..3b2aa17b7aa6a1a09ae5804e3e62a150834f0c47 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2023 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
 // EXTERNAL INCLUDES
 #include <dali/public-api/animation/constraints.h>
 #include <dali/public-api/common/vector-wrapper.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
 #include <stdarg.h>
 #include <cstring>
 #include <fstream>
@@ -85,12 +86,12 @@ std::string FormatString(const char* format, ...)
 
 std::string LoadTextFile(const char* path, bool* fail)
 {
-  std::ifstream inFile(path);
-  if(inFile)
+  std::streampos     fileSize;
+  Dali::Vector<char> fileContent;
+
+  if(FileLoader::ReadFile(path, fileSize, fileContent, FileLoader::TEXT))
   {
-    std::istreambuf_iterator<char> eos;
-    std::istreambuf_iterator<char> i(inFile.rdbuf());
-    return std::string(i, eos);
+    return std::string(fileContent.Begin(), fileSize);
   }
   else if(fail)
   {