Sync with 5.4.2
[deliverable/titan.core.git] / compiler2 / ttcn3 / Ttcn2Json.cc
CommitLineData
3abe9331 1///////////////////////////////////////////////////////////////////////////////
2// Copyright (c) 2000-2015 Ericsson Telecom AB
3// All rights reserved. This program and the accompanying materials
4// are made available under the terms of the Eclipse Public License v1.0
5// which accompanies this distribution, and is available at
6// http://www.eclipse.org/legal/epl-v10.html
7///////////////////////////////////////////////////////////////////////////////
8
970ed795
EL
9#include "Ttcn2Json.hh"
10
11#include "compiler.h"
12
13#include "../AST.hh"
14#include "../../common/JSON_Tokenizer.hh"
3f84031e 15#include "../Value.hh"
16#include "../Valuestuff.hh"
970ed795
EL
17
18// forward declarations
19namespace Common {
20 class Type;
21}
22
23namespace Ttcn {
24
25Ttcn2Json::Ttcn2Json(Common::Modules* p_modules, const char* p_schema_name)
26: modules(p_modules)
27{
28 boolean is_temporary;
29 FILE* file = open_output_file(p_schema_name, &is_temporary);
30
31 JSON_Tokenizer json(true);
32
33 create_schema(json);
34
35 fprintf(file, "%s\n", json.get_buffer());
36
37 close_output_file(p_schema_name, file, is_temporary, 0);
38}
39
40void Ttcn2Json::create_schema(JSON_Tokenizer& json)
41{
42 // top-level object start
43 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
44
3abe9331 45 // insert the schema header
46 json.put_next_token(JSON_TOKEN_NAME, "$schema");
47 json.put_next_token(JSON_TOKEN_STRING, "\"http://json-schema.org/draft-04/schema#\"");
48
970ed795
EL
49 // start of type definitions
50 json.put_next_token(JSON_TOKEN_NAME, "definitions");
51 json.put_next_token(JSON_TOKEN_OBJECT_START, NULL);
52
af710487 53 // insert module names and schemas for types; gather references to types and
54 // JSON encoding/decoding function information
55 map<Common::Type*, JSON_Tokenizer> json_refs;
56 modules->generate_json_schema(json, json_refs);
970ed795
EL
57
58 // end of type definitions
59 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
af710487 60
61 if (!json_refs.empty()) {
62 // top-level "anyOf" structure containing references to the types the schema validates
63 // don't insert an empty "anyOf" if there are no references
64 json.put_next_token(JSON_TOKEN_NAME, "anyOf");
65 json.put_next_token(JSON_TOKEN_ARRAY_START, NULL);
66
67 // close schema segments and add them to the main schema
68 for (size_t i = 0; i < json_refs.size(); ++i) {
69 JSON_Tokenizer* segment = json_refs.get_nth_elem(i);
70 segment->put_next_token(JSON_TOKEN_OBJECT_END, NULL);
71 insert_schema(json, *segment);
72 delete segment;
73 }
74 json_refs.clear();
75
76 // end of the "anyOf" structure
77 json.put_next_token(JSON_TOKEN_ARRAY_END, NULL);
970ed795 78 }
970ed795
EL
79
80 // top-level object end
81 json.put_next_token(JSON_TOKEN_OBJECT_END, NULL);
82}
83
84void Ttcn2Json::insert_schema(JSON_Tokenizer& to, JSON_Tokenizer& from)
85{
86 json_token_t token = JSON_TOKEN_NONE;
87 char* value_str = NULL;
88 size_t value_len = 0;
89 char temp = 0;
90
91 do {
92 from.get_next_token(&token, &value_str, &value_len);
93
94 if (token == JSON_TOKEN_ERROR) {
95 FATAL_ERROR("Ttcn2Json::insert_schema");
96 }
97
98 if (value_str != NULL) {
99 // put_next_token expects a null terminated string, save the next character
100 // and set it to null
101 temp = value_str[value_len];
102 value_str[value_len] = 0;
103 }
104
105 to.put_next_token(token, value_str);
106
107 if (value_str != NULL) {
108 // put the original character back to its place
109 value_str[value_len] = temp;
110 }
111 } while (token != JSON_TOKEN_NONE);
112}
113
3f84031e 114JsonOmitCombination::JsonOmitCombination(Common::Value* p_top_level)
115{
116 parse_value(p_top_level->get_value_refd_last());
117}
118
119JsonOmitCombination::~JsonOmitCombination()
120{
121 for (size_t i = 0; i < combinations.size(); ++i) {
122 delete combinations.get_nth_elem(i);
123 }
124 combinations.clear();
125}
126
127bool JsonOmitCombination::next(int current_value /* = 0 */)
128{
129 if ((size_t)current_value == combinations.size()) {
130 return false;
131 }
132 Common::Value* val = combinations.get_nth_key(current_value);
133 int* omitted_fields = combinations.get_nth_elem(current_value);
134 for (size_t i = 0; i < val->get_nof_comps(); ++i) {
135 if (omitted_fields[i] == OMITTED_ABSENT) {
136 // ABSENT (zero bit) found, set it to NULL (one bit) and reset all previous
137 // NULLs (ones) to ABSENTs (zeros), first in this value ...
138 omitted_fields[i] = OMITTED_NULL;
139 for (size_t j = 0; j < i; ++j) {
140 if (omitted_fields[j] == OMITTED_NULL) {
141 omitted_fields[j] = OMITTED_ABSENT;
142 }
143 }
144 // ... and then in all previous record values
145 reset_previous(current_value);
146 return true;
147 }
148 }
149 // no new combinations in this value, check the next one
150 return next(current_value + 1);
151}
152
153JsonOmitCombination::omit_state_t JsonOmitCombination::get_state(
154 Common::Value* p_rec_value, size_t p_comp) const
155{
156 return (JsonOmitCombination::omit_state_t)combinations[p_rec_value][p_comp];
157}
158
159void JsonOmitCombination::parse_value(Common::Value* p_value)
160{
161 switch (p_value->get_valuetype()) {
162 case Common::Value::V_SEQ:
163 case Common::Value::V_SET: {
164 size_t len = p_value->get_nof_comps();
165 int* omitted_fields = new int[len]; // stores one combination
166 for (size_t i = 0; i < len; ++i) {
167 Common::Value* val = p_value->get_se_comp_byIndex(i)->get_value();
168 if (val->get_valuetype() == Common::Value::V_OMIT) {
169 // all omitted fields are absent in the first combination
170 omitted_fields[i] = OMITTED_ABSENT;
171 }
172 else {
173 omitted_fields[i] = NOT_OMITTED;
174 }
175 parse_value(val->get_value_refd_last());
176 }
177 combinations.add(p_value, omitted_fields);
178 break; }
179 case Common::Value::V_SEQOF:
180 case Common::Value::V_SETOF:
181 for (size_t i = 0; i < p_value->get_nof_comps(); ++i) {
182 parse_value(p_value->get_comp_byIndex(i)->get_value_refd_last());
183 }
184 break;
185 case Common::Value::V_CHOICE:
186 parse_value(p_value->get_alt_value()->get_value_refd_last());
187 default:
188 break;
189 }
190}
191
192void JsonOmitCombination::reset_previous(int value_count)
193{
194 for (int i = 0; i < value_count; ++i) {
195 Common::Value* val = combinations.get_nth_key(i);
196 int* omitted_fields = combinations.get_nth_elem(i);
197 for (size_t j = 0; j < val->get_nof_comps(); ++j) {
198 if (omitted_fields[j] == OMITTED_NULL) {
199 omitted_fields[j] = OMITTED_ABSENT;
200 }
201 }
202 }
203}
204
970ed795
EL
205} // namespace
206
This page took 0.031814 seconds and 5 git commands to generate.