1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/imaging/hio/dictionary.h"
26 
27 #include "pxr/base/js/converter.h"
28 #include "pxr/base/js/json.h"
29 #include "pxr/base/tf/debug.h"
30 
31 PXR_NAMESPACE_OPEN_SCOPE
32 
33 
34 using namespace std;
35 
36 
37 TF_DEBUG_CODES(
38 
39     HIO_DEBUG_DICTIONARY
40 
41 );
42 
43 
TF_REGISTRY_FUNCTION(TfDebug)44 TF_REGISTRY_FUNCTION(TfDebug)
45 {
46     TF_DEBUG_ENVIRONMENT_SYMBOL(HIO_DEBUG_DICTIONARY,
47         "glslfx dictionary parsing");
48 }
49 
50 static VtDictionary
_Hio_GetDictionaryFromJSON(const string & input,string * errorStr)51 _Hio_GetDictionaryFromJSON(
52     const string &input,
53     string *errorStr )
54 {
55     if (input.empty())
56     {
57         const char *errorMsg = "Cannot create VtDictionary from empty string";
58         TF_DEBUG(HIO_DEBUG_DICTIONARY).Msg("%s", errorMsg);
59 
60         if( errorStr ) {
61             *errorStr = errorMsg;
62         }
63         return VtDictionary();
64     }
65 
66     // Note Js library doesn't allow comments.  Strip comments as we do
67     // for plugInfo files.
68     //
69     // XXX: This may not be worth the cost.
70     //
71     std::vector<std::string> filtered = TfStringSplit(input, "\n");
72     for (auto & line : filtered) {
73         // Clear comment lines but keep them to maintain line numbers for errors
74         if (line.find('#') < line.find_first_not_of(" \t#"))
75             line.clear();
76     }
77 
78     JsParseError error;
79     JsValue jsdict = JsParseString(TfStringJoin(filtered, "\n"), &error);
80 
81     if (jsdict.IsNull()) {
82         if (errorStr || TfDebug::IsEnabled(HIO_DEBUG_DICTIONARY)) {
83             std::string errorMessageStr = TfStringPrintf(
84                 "Failed to extract dictionary from input (line %d, col %d): %s",
85                 error.line, error.column, error.reason.c_str());
86             if (errorStr) {
87                 *errorStr = errorMessageStr;
88             }
89             TF_DEBUG(HIO_DEBUG_DICTIONARY).Msg("%s", errorMessageStr.c_str());
90         }
91         return VtDictionary();
92     }
93 
94     if (!jsdict.IsObject()) {
95         if (errorStr || TfDebug::IsEnabled(HIO_DEBUG_DICTIONARY)) {
96             std::string errorMessageStr = TfStringPrintf(
97                 "Input string did not evaluate to a JSON dictionary:\n%s\n",
98                 input.c_str());
99             if (errorStr) {
100                 *errorStr = errorMessageStr;
101             }
102             TF_DEBUG(HIO_DEBUG_DICTIONARY).Msg("%s", errorMessageStr.c_str());
103         }
104         return VtDictionary();
105     }
106 
107     const VtValue vtdict =
108         JsValueTypeConverter<VtValue, VtDictionary, /*UseInt64*/false>::Convert(jsdict);
109     return vtdict.IsHolding<VtDictionary>() ?
110         vtdict.UncheckedGet<VtDictionary>() : VtDictionary();
111 }
112 
113 
114 VtDictionary
Hio_GetDictionaryFromInput(const string & input,const string & filename,string * errorStr)115 Hio_GetDictionaryFromInput(
116     const string &input,
117     const string &filename,
118     string *errorStr )
119 {
120     std::string jsError;
121     VtDictionary ret = _Hio_GetDictionaryFromJSON(input, &jsError);
122 
123     if (jsError.empty()) {
124         // JSON succeeded, great, we're done.
125         return ret;
126     }
127 
128     // If the file has errors, report the errors from JSON as that is the new
129     // format that we're expected to conform to.
130     if (errorStr) {
131         *errorStr = jsError;
132     }
133     return VtDictionary();
134 }
135 
136 PXR_NAMESPACE_CLOSE_SCOPE
137 
138