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 :
13 : #include <com/sun/star/embed/ElementModes.hpp>
14 : #include <com/sun/star/embed/XTransactedObject.hpp>
15 : #include <com/sun/star/document/XStorageBasedDocument.hpp>
16 : #include <com/sun/star/embed/XStorage.hpp>
17 : #include <osl/file.hxx>
18 : #include <comphelper/processfactory.hxx>
19 : #include <tools/urlobj.hxx>
20 : #include <ucbhelper/content.hxx>
21 :
22 : #include <boost/property_tree/ptree.hpp>
23 : #include <boost/property_tree/json_parser.hpp>
24 : #include <boost/foreach.hpp>
25 :
26 : #include <string>
27 : #include <vector>
28 :
29 : using namespace ::com::sun::star;
30 : using namespace boost::property_tree;
31 :
32 : namespace avmedia {
33 :
34 0 : static void lcl_EmbedExternals(const OUString& rSourceURL, uno::Reference<embed::XStorage> xSubStorage, ::ucbhelper::Content& rContent)
35 : {
36 : // Create a temp file with which json parser can work.
37 0 : OUString sTempFileURL;
38 : const ::osl::FileBase::RC aErr =
39 0 : ::osl::FileBase::createTempFile(0, 0, &sTempFileURL);
40 0 : if (::osl::FileBase::E_None != aErr)
41 : {
42 : SAL_WARN("avmedia.model", "cannot create temp file");
43 0 : return;
44 : }
45 : try
46 : {
47 : // Write json content to the temp file
48 : ::ucbhelper::Content aTempContent(sTempFileURL,
49 : uno::Reference<ucb::XCommandEnvironment>(),
50 0 : comphelper::getProcessComponentContext());
51 0 : aTempContent.writeStream(rContent.openStream(), true);
52 : }
53 0 : catch (uno::Exception const& e)
54 : {
55 : SAL_WARN("avmedia.model", "exception: '" << e.Message << "'");
56 0 : return;
57 : }
58 :
59 : // Convert URL to a file path for loading
60 0 : const INetURLObject aURLObj(sTempFileURL);
61 0 : std::string sUrl = OUStringToOString( aURLObj.getFSysPath(INetURLObject::FSYS_DETECT), RTL_TEXTENCODING_UTF8 ).getStr();
62 :
63 : // Parse json, read externals' URI and modify this relative URI's so they remain valid in the new context.
64 0 : std::vector<std::string> vExternals;
65 0 : ptree aTree;
66 : try
67 : {
68 0 : json_parser::read_json( sUrl, aTree );
69 :
70 : // Buffers for geometry and animations
71 0 : BOOST_FOREACH(ptree::value_type &rVal,aTree.get_child("buffers"))
72 : {
73 0 : const std::string sBufferUri(rVal.second.get<std::string>("path"));
74 0 : vExternals.push_back(sBufferUri);
75 : // Change path: make it contain only a file name
76 0 : aTree.put("buffers." + rVal.first + ".path.",sBufferUri.substr(sBufferUri.find_last_of('/')+1));
77 0 : }
78 : // Images for textures
79 0 : BOOST_FOREACH(ptree::value_type &rVal,aTree.get_child("images"))
80 : {
81 0 : const std::string sImageUri(rVal.second.get<std::string>("path"));
82 0 : vExternals.push_back(sImageUri);
83 : // Change path: make it contain only a file name
84 0 : aTree.put("images." + rVal.first + ".path.",sImageUri.substr(sImageUri.find_last_of('/')+1));
85 0 : }
86 : // Shaders (contains names only)
87 0 : BOOST_FOREACH(ptree::value_type &rVal,aTree.get_child("programs"))
88 : {
89 0 : vExternals.push_back(rVal.second.get<std::string>("fragmentShader") + ".glsl");
90 0 : vExternals.push_back(rVal.second.get<std::string>("vertexShader") + ".glsl");
91 : }
92 :
93 : // Write out modified json
94 0 : json_parser::write_json( sUrl, aTree );
95 : }
96 0 : catch ( boost::exception const& )
97 : {
98 : SAL_WARN("avmedia.model", "failed to parse json file");
99 0 : return;
100 : }
101 :
102 : // Reload json with modified path to external resources
103 0 : rContent = ::ucbhelper::Content("file://" + OUString::createFromAscii(sUrl.c_str()),
104 : uno::Reference<ucb::XCommandEnvironment>(),
105 0 : comphelper::getProcessComponentContext());
106 :
107 : // Store all external files next to the json file
108 0 : for( std::vector<std::string>::iterator aCIter = vExternals.begin(); aCIter != vExternals.end(); ++aCIter )
109 : {
110 0 : const OUString sAbsURL = INetURLObject::GetAbsURL(rSourceURL,OUString::createFromAscii(aCIter->c_str()));
111 :
112 : ::ucbhelper::Content aContent(sAbsURL,
113 : uno::Reference<ucb::XCommandEnvironment>(),
114 0 : comphelper::getProcessComponentContext());
115 :
116 : uno::Reference<io::XStream> const xStream(
117 0 : CreateStream(xSubStorage, GetFilename(sAbsURL)), uno::UNO_SET_THROW);
118 : uno::Reference<io::XOutputStream> const xOutStream(
119 0 : xStream->getOutputStream(), uno::UNO_SET_THROW);
120 :
121 0 : if (!aContent.openStream(xOutStream))
122 : {
123 : SAL_WARN("avmedia.model", "openStream to storage failed");
124 0 : return;
125 : }
126 0 : }
127 : }
128 :
129 0 : bool Embed3DModel( const uno::Reference<frame::XModel>& xModel,
130 : const OUString& rSourceURL, OUString& o_rEmbeddedURL)
131 : {
132 : try
133 : {
134 : ::ucbhelper::Content aSourceContent(rSourceURL,
135 : uno::Reference<ucb::XCommandEnvironment>(),
136 0 : comphelper::getProcessComponentContext());
137 :
138 : // Base storage
139 : uno::Reference<document::XStorageBasedDocument> const xSBD(xModel,
140 0 : uno::UNO_QUERY_THROW);
141 : uno::Reference<embed::XStorage> const xStorage(
142 0 : xSBD->getDocumentStorage(), uno::UNO_QUERY_THROW);
143 :
144 : // Model storage
145 0 : const OUString sModel("Model");
146 : uno::Reference<embed::XStorage> const xModelStorage(
147 0 : xStorage->openStorageElement(sModel, embed::ElementModes::WRITE));
148 :
149 : // Own storage of the corresponding model
150 0 : const OUString sFilename(GetFilename(rSourceURL));
151 0 : const OUString sGLTFDir(sFilename.copy(0,sFilename.lastIndexOf('.')));
152 : uno::Reference<embed::XStorage> const xSubStorage(
153 0 : xModelStorage->openStorageElement(sGLTFDir, embed::ElementModes::WRITE));
154 :
155 : // Embed external resources
156 0 : lcl_EmbedExternals(rSourceURL, xSubStorage, aSourceContent);
157 :
158 : // Save model file (.json)
159 : uno::Reference<io::XStream> const xStream(
160 0 : CreateStream(xSubStorage, sFilename), uno::UNO_SET_THROW);
161 : uno::Reference<io::XOutputStream> const xOutStream(
162 0 : xStream->getOutputStream(), uno::UNO_SET_THROW);
163 :
164 0 : if (!aSourceContent.openStream(xOutStream))
165 : {
166 : SAL_INFO("avmedia.model", "openStream to storage failed");
167 0 : return false;
168 : }
169 :
170 0 : const uno::Reference<embed::XTransactedObject> xSubTransaction(xSubStorage, uno::UNO_QUERY);
171 0 : if (xSubTransaction.is())
172 : {
173 0 : xSubTransaction->commit();
174 : }
175 0 : const uno::Reference<embed::XTransactedObject> xModelTransaction(xModelStorage, uno::UNO_QUERY);
176 0 : if (xModelTransaction.is())
177 : {
178 0 : xModelTransaction->commit();
179 : }
180 0 : const uno::Reference<embed::XTransactedObject> xTransaction(xStorage, uno::UNO_QUERY);
181 0 : if (xTransaction.is())
182 : {
183 0 : xTransaction->commit();
184 : }
185 :
186 0 : o_rEmbeddedURL = "vnd.sun.star.Package:" + sModel + "/" + sGLTFDir + "/" + sFilename;
187 0 : return true;
188 : }
189 0 : catch (uno::Exception const&)
190 : {
191 : SAL_WARN("avmedia.model", "Exception while trying to embed model");
192 : }
193 0 : return false;
194 : }
195 :
196 0 : } // namespace avemdia
197 :
198 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|