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

Generated by: LCOV version 1.11