LCOV - code coverage report
Current view: top level - avmedia/source/framework - modeltools.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 1 121 0.8 %
Date: 2014-11-03 Functions: 2 7 28.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  */
       9             : 
      10             : #include <avmedia/modeltools.hxx>
      11             : #include <avmedia/mediaitem.hxx>
      12             : #include "mediamisc.hxx"
      13             : 
      14             : #include <com/sun/star/embed/ElementModes.hpp>
      15             : #include <com/sun/star/embed/XTransactedObject.hpp>
      16             : #include <com/sun/star/document/XStorageBasedDocument.hpp>
      17             : #include <com/sun/star/embed/XStorage.hpp>
      18             : #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
      19             : #include <osl/file.hxx>
      20             : #include <comphelper/processfactory.hxx>
      21             : #include <tools/urlobj.hxx>
      22             : #include <ucbhelper/content.hxx>
      23             : #include <unotools/localfilehelper.hxx>
      24             : #include <unotools/tempfile.hxx>
      25             : #include <unotools/ucbstreamhelper.hxx>
      26             : 
      27             : #include <boost/property_tree/ptree.hpp>
      28             : #include <boost/property_tree/json_parser.hpp>
      29             : #include <boost/foreach.hpp>
      30             : #include <boost/optional.hpp>
      31             : 
      32             : #include <config_features.h>
      33             : 
      34             : #if HAVE_FEATURE_COLLADA
      35             : #include <collada_headers.hxx>
      36             : #include <GLTFAsset.h>
      37             : #endif
      38             : 
      39             : #include <string>
      40             : #include <vector>
      41             : 
      42             : using namespace ::com::sun::star;
      43             : using namespace boost::property_tree;
      44             : 
      45             : namespace avmedia {
      46             : 
      47             : #if HAVE_FEATURE_COLLADA
      48             : 
      49           0 : static void lcl_UnzipKmz(const OUString& rSourceURL, const OUString& rOutputFolderURL, OUString& o_rDaeFileURL)
      50             : {
      51           0 :     o_rDaeFileURL = OUString();
      52             :     uno::Reference<packages::zip::XZipFileAccess2> xNameAccess =
      53           0 :         packages::zip::ZipFileAccess::createWithURL(comphelper::getProcessComponentContext(), rSourceURL);
      54           0 :     uno::Sequence< OUString > aNames = xNameAccess->getElementNames();
      55           0 :     for( sal_Int32 i = 0; i < aNames.getLength(); ++i )
      56             :     {
      57           0 :         const OUString sCopy = rOutputFolderURL + "/" + aNames[i];
      58           0 :         if( aNames[i].endsWithIgnoreAsciiCase(".dae") )
      59           0 :             o_rDaeFileURL = sCopy;
      60             : 
      61           0 :         uno::Reference<io::XInputStream> xInputStream(xNameAccess->getByName(aNames[i]), uno::UNO_QUERY);
      62             : 
      63             :         ::ucbhelper::Content aCopyContent(sCopy,
      64             :             uno::Reference<ucb::XCommandEnvironment>(),
      65           0 :             comphelper::getProcessComponentContext());
      66             : 
      67           0 :         aCopyContent.writeStream(xInputStream, true);
      68           0 :     }
      69           0 : }
      70             : 
      71           0 : bool KmzDae2Gltf(const OUString& rSourceURL, OUString& o_rOutput)
      72             : {
      73           0 :     o_rOutput = OUString();
      74           0 :     const bool bIsDAE = rSourceURL.endsWithIgnoreAsciiCase(".dae");
      75           0 :     const bool bIsKMZ = rSourceURL.endsWithIgnoreAsciiCase(".kmz");
      76           0 :     if( !bIsDAE && !bIsKMZ )
      77             :     {
      78             :         SAL_WARN("avmedia.opengl", "KmzDae2Gltf converter got a file with wrong extension\n" << rSourceURL);
      79           0 :         return false;
      80             :     }
      81             : 
      82             :     // Create a temporary folder for conversion
      83           0 :     OUString sOutput;
      84           0 :     ::utl::LocalFileHelper::ConvertPhysicalNameToURL(::utl::TempFile::CreateTempName(), sOutput);
      85             :     // remove .tmp extension
      86           0 :     sOutput = sOutput.copy(0, sOutput.getLength()-4);
      87             : 
      88           0 :     std::shared_ptr <GLTF::GLTFAsset> asset(new GLTF::GLTFAsset());
      89           0 :     asset->setBundleOutputPath(OUStringToOString( sOutput, RTL_TEXTENCODING_UTF8 ).getStr());
      90             : 
      91             :     // If *.dae file is not in the local file system, then copy it to a temp folder for the conversion
      92           0 :     OUString sInput = rSourceURL;
      93           0 :     const INetURLObject aSourceURLObj(rSourceURL);
      94           0 :     if( aSourceURLObj.GetProtocol() != INET_PROT_FILE )
      95             :     {
      96             :         try
      97             :         {
      98             :             ::ucbhelper::Content aSourceContent(rSourceURL,
      99             :                 uno::Reference<ucb::XCommandEnvironment>(),
     100           0 :                 comphelper::getProcessComponentContext());
     101             : 
     102           0 :             const OUString sTarget = sOutput + "/" + GetFilename(rSourceURL);
     103             :             ::ucbhelper::Content aTempContent(sTarget,
     104             :                 uno::Reference<ucb::XCommandEnvironment>(),
     105           0 :                 comphelper::getProcessComponentContext());
     106             : 
     107           0 :             aTempContent.writeStream(aSourceContent.openStream(), true);
     108           0 :             sInput = sTarget;
     109             :         }
     110           0 :         catch (const uno::Exception&)
     111             :         {
     112             :             SAL_WARN("avmedia.opengl", "Exception while trying to copy source file to the temp folder for conversion:\n" << sInput);
     113           0 :             return false;
     114             :         }
     115             :     }
     116             : 
     117           0 :     asset->setInputFilePath(OUStringToOString( sInput, RTL_TEXTENCODING_UTF8 ).getStr());
     118             : 
     119           0 :     if (bIsKMZ)
     120             :     {
     121           0 :         OUString sDaeFilePath;
     122           0 :         lcl_UnzipKmz(sInput, sOutput, sDaeFilePath);
     123           0 :         if ( sDaeFilePath.isEmpty() )
     124             :         {
     125             :             SAL_WARN("avmedia.opengl", "Cannot find dae file in kmz:\n" << rSourceURL);
     126           0 :             return false;
     127             :         }
     128             : 
     129           0 :         asset->setInputFilePath(OUStringToOString( sDaeFilePath, RTL_TEXTENCODING_UTF8 ).getStr());
     130             :     }
     131             : 
     132           0 :     GLTF::COLLADA2GLTFWriter writer(asset);
     133           0 :     writer.write();
     134             :     // Path to the .json file created by COLLADA2GLTFWriter
     135           0 :     o_rOutput = sOutput + "/" + GetFilename(sOutput) + ".json";
     136           0 :     return true;
     137             : }
     138             : #endif
     139             : 
     140           0 : static void lcl_EmbedExternals(const OUString& rSourceURL, uno::Reference<embed::XStorage> xSubStorage, ::ucbhelper::Content& rContent)
     141             : {
     142             :     // Create a temp file with which json parser can work.
     143           0 :     OUString sTempFileURL;
     144             :     const ::osl::FileBase::RC  aErr =
     145           0 :         ::osl::FileBase::createTempFile(0, 0, &sTempFileURL);
     146           0 :     if (::osl::FileBase::E_None != aErr)
     147             :     {
     148             :         SAL_WARN("avmedia.opengl", "Cannot create temp file");
     149           0 :         return;
     150             :     }
     151             :     try
     152             :     {
     153             :         // Write json content to the temp file
     154             :         ::ucbhelper::Content aTempContent(sTempFileURL,
     155             :             uno::Reference<ucb::XCommandEnvironment>(),
     156           0 :             comphelper::getProcessComponentContext());
     157           0 :         aTempContent.writeStream(rContent.openStream(), true);
     158             :     }
     159           0 :     catch (uno::Exception const& e)
     160             :     {
     161             :         SAL_WARN("avmedia.opengl", "Exception: '" << e.Message << "'");
     162           0 :         return;
     163             :     }
     164             : 
     165             :     // Convert URL to a file path for loading
     166           0 :     const INetURLObject aURLObj(sTempFileURL);
     167           0 :     std::string sUrl = OUStringToOString( aURLObj.getFSysPath(INetURLObject::FSYS_DETECT), RTL_TEXTENCODING_UTF8 ).getStr();
     168             : 
     169             :     // Parse json, read externals' URI and modify this relative URI's so they remain valid in the new context.
     170           0 :     std::vector<std::string> vExternals;
     171           0 :     ptree aTree;
     172             :     try
     173             :     {
     174           0 :         json_parser::read_json( sUrl, aTree );
     175             : 
     176             :         // Buffers for geometry and animations
     177           0 :         BOOST_FOREACH(ptree::value_type &rVal,aTree.get_child("buffers"))
     178             :         {
     179           0 :             const std::string sBufferUri(rVal.second.get<std::string>("path"));
     180           0 :             vExternals.push_back(sBufferUri);
     181             :             // Change path: make it contain only a file name
     182           0 :             aTree.put("buffers." + rVal.first + ".path.",sBufferUri.substr(sBufferUri.find_last_of('/')+1));
     183           0 :         }
     184             :         // Images for textures
     185           0 :         boost::optional< ptree& > aImages = aTree.get_child_optional("images");
     186           0 :         if( aImages )
     187             :         {
     188           0 :             BOOST_FOREACH(ptree::value_type &rVal,aImages.get())
     189             :             {
     190           0 :                 const std::string sImageUri(rVal.second.get<std::string>("path"));
     191           0 :                 if( !sImageUri.empty() )
     192             :                 {
     193           0 :                     vExternals.push_back(sImageUri);
     194             :                     // Change path: make it contain only a file name
     195           0 :                     aTree.put("images." + rVal.first + ".path.",sImageUri.substr(sImageUri.find_last_of('/')+1));
     196             :                 }
     197           0 :             }
     198             :         }
     199             :         // Shaders (contains names only)
     200           0 :         BOOST_FOREACH(ptree::value_type &rVal,aTree.get_child("programs"))
     201             :         {
     202           0 :             vExternals.push_back(rVal.second.get<std::string>("fragmentShader") + ".glsl");
     203           0 :             vExternals.push_back(rVal.second.get<std::string>("vertexShader") + ".glsl");
     204             :         }
     205             : 
     206             :         // Write out modified json
     207           0 :         json_parser::write_json( sUrl, aTree );
     208             :     }
     209           0 :     catch ( boost::exception const& )
     210             :     {
     211             :         SAL_WARN("avmedia.opengl", "Exception while parsing *.json file");
     212           0 :         return;
     213             :     }
     214             : 
     215             :     // Reload json with modified path to external resources
     216           0 :     rContent = ::ucbhelper::Content(sTempFileURL,
     217             :         uno::Reference<ucb::XCommandEnvironment>(),
     218           0 :         comphelper::getProcessComponentContext());
     219             : 
     220             :     // Store all external files next to the json file
     221           0 :     for( std::vector<std::string>::iterator aCIter = vExternals.begin(); aCIter != vExternals.end(); ++aCIter )
     222             :     {
     223           0 :         const OUString sAbsURL = INetURLObject::GetAbsURL(rSourceURL,OUString::createFromAscii(aCIter->c_str()));
     224             : 
     225             :         ::ucbhelper::Content aContent(sAbsURL,
     226             :                 uno::Reference<ucb::XCommandEnvironment>(),
     227           0 :                 comphelper::getProcessComponentContext());
     228             : 
     229             :         uno::Reference<io::XStream> const xStream(
     230           0 :             CreateStream(xSubStorage, GetFilename(sAbsURL)), uno::UNO_SET_THROW);
     231             :         uno::Reference<io::XOutputStream> const xOutStream(
     232           0 :             xStream->getOutputStream(), uno::UNO_SET_THROW);
     233             : 
     234           0 :         if (!aContent.openStream(xOutStream))
     235             :         {
     236             :             SAL_WARN("avmedia.opengl", "openStream to storage failed");
     237           0 :             return;
     238             :         }
     239           0 :     }
     240             : }
     241             : 
     242           0 : bool Embed3DModel( const uno::Reference<frame::XModel>& xModel,
     243             :         const OUString& rSourceURL, OUString& o_rEmbeddedURL)
     244             : {
     245           0 :     OUString sSource = rSourceURL;
     246             : 
     247             : #if HAVE_FEATURE_COLLADA
     248           0 :     if( !rSourceURL.endsWithIgnoreAsciiCase(".json") )
     249           0 :         KmzDae2Gltf(rSourceURL, sSource);
     250             : #endif
     251             : 
     252             :     try
     253             :     {
     254             :         ::ucbhelper::Content aSourceContent(sSource,
     255             :                 uno::Reference<ucb::XCommandEnvironment>(),
     256           0 :                 comphelper::getProcessComponentContext());
     257             : 
     258             :         // Base storage
     259             :         uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
     260           0 :                 uno::UNO_QUERY_THROW);
     261             :         uno::Reference<embed::XStorage> const xStorage(
     262           0 :                 xSBD->getDocumentStorage(), uno::UNO_QUERY_THROW);
     263             : 
     264             :         // Model storage
     265           0 :         const OUString sModel("Models");
     266             :         uno::Reference<embed::XStorage> const xModelStorage(
     267           0 :             xStorage->openStorageElement(sModel, embed::ElementModes::WRITE));
     268             : 
     269             :         // Own storage of the corresponding model
     270           0 :         const OUString sFilename(GetFilename(sSource));
     271           0 :         const OUString sGLTFDir(sFilename.copy(0,sFilename.lastIndexOf('.')));
     272             :         uno::Reference<embed::XStorage> const xSubStorage(
     273           0 :             xModelStorage->openStorageElement(sGLTFDir, embed::ElementModes::WRITE));
     274             : 
     275             :         // Embed external resources
     276           0 :         lcl_EmbedExternals(sSource, xSubStorage, aSourceContent);
     277             : 
     278             :         // Save model file (.json)
     279             :         uno::Reference<io::XStream> const xStream(
     280           0 :             CreateStream(xSubStorage, sFilename), uno::UNO_SET_THROW);
     281             :         uno::Reference<io::XOutputStream> const xOutStream(
     282           0 :             xStream->getOutputStream(), uno::UNO_SET_THROW);
     283             : 
     284           0 :         if (!aSourceContent.openStream(xOutStream))
     285             :         {
     286             :             SAL_WARN("avmedia.opengl", "openStream to storage failed");
     287           0 :             return false;
     288             :         }
     289             : 
     290           0 :         const uno::Reference<embed::XTransactedObject> xSubTransaction(xSubStorage, uno::UNO_QUERY);
     291           0 :         if (xSubTransaction.is())
     292             :         {
     293           0 :             xSubTransaction->commit();
     294             :         }
     295           0 :         const uno::Reference<embed::XTransactedObject> xModelTransaction(xModelStorage, uno::UNO_QUERY);
     296           0 :         if (xModelTransaction.is())
     297             :         {
     298           0 :             xModelTransaction->commit();
     299             :         }
     300           0 :         const uno::Reference<embed::XTransactedObject> xTransaction(xStorage, uno::UNO_QUERY);
     301           0 :         if (xTransaction.is())
     302             :         {
     303           0 :             xTransaction->commit();
     304             :         }
     305             : 
     306           0 :         o_rEmbeddedURL = "vnd.sun.star.Package:" + sModel + "/" + sGLTFDir + "/" + sFilename;
     307           0 :         return true;
     308             :     }
     309           0 :     catch (uno::Exception const&)
     310             :     {
     311             :         SAL_WARN("avmedia.opengl", "Exception while trying to embed model");
     312             :     }
     313           0 :     return false;
     314             : }
     315             : 
     316           0 : bool IsModel(const OUString& rMimeType)
     317             : {
     318           0 :     return rMimeType == AVMEDIA_MIMETYPE_JSON;
     319             : }
     320             : 
     321         651 : } // namespace avemdia
     322             : 
     323             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10