1#!/usr/bin/python 2 3# ===================================== 4# Copyright 2017-2023, Andrew Lindesay 5# Distributed under the terms of the MIT License. 6# ===================================== 7 8# This simple tool will read a JSON schema and will then generate 9# some model objects that can be used to hold the data-structure 10# in the C++ environment. 11 12import json 13import argparse 14import os 15import hdsjsonschemacommon 16import ustache 17 18 19HEADER_TEMPLATE = """ 20/* 21 * Generated Model Object for {{cppname}} 22 */ 23 24#ifndef GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 25#define GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 26 27#include <ObjectList.h> 28#include <String.h> 29 30{{#referencedclasscpptypes}}#include "{{.}}.h" 31{{/referencedclasscpptypes}} 32 33 34class {{cppname}} { 35public: 36 {{cppname}}(); 37 virtual ~{{cppname}}(); 38 39 void Reset(); 40{{#propertyarray}}{{#property.iscppscalartype}} 41 {{property.cpptype}} {{property.cppname}}(); 42 void Set{{property.cppname}}({{property.cpptype}} value); 43 void Set{{property.cppname}}Null(); 44 bool {{property.cppname}}IsNull(); 45{{/property.iscppscalartype}}{{#property.isarray}} 46 void AddTo{{property.cppname}}({{property.items.cpptype}}* value); 47 void Set{{property.cppname}}({{property.cpptype}}* value); 48 int32 Count{{property.cppname}}(); 49 {{property.items.cpptype}}* {{property.cppname}}ItemAt(int32 index); 50 bool {{property.cppname}}IsNull(); 51{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}} 52 {{property.cpptype}}* {{property.cppname}}(); 53 void Set{{property.cppname}}({{property.cpptype}}* value); 54 void Set{{property.cppname}}Null(); 55 bool {{property.cppname}}IsNull(); 56{{/property.iscppnonscalarnoncollectiontype}} 57{{/propertyarray}} 58 59public: 60{{#propertyarray}} static const uint16 k{{property.cppname}}Bitmask; 61{{/propertyarray}} 62 63private: 64 uint16 fHasValueBitmask; 65{{#propertyarray}} {{property.cpptype}}{{^property.iscppscalartype}}*{{/property.iscppscalartype}} {{property.cppmembername}}; 66{{/propertyarray}} 67}; 68 69#endif // GEN_JSON_SCHEMA_MODEL__{{cppnameupper}}_H 70""" 71 72IMPLEMENTATION_TEMPLATE = """ 73/* 74 * Generated Model Object for {{cppname}} 75 */ 76 77#include "{{cppname}}.h" 78 79 80{{#propertyarray}}/*static*/ const uint16 {{cppname}}::k{{property.cppname}}Bitmask = {{cppbitmaskexpression}}; 81{{/propertyarray}} 82 83 84{{cppname}}::{{cppname}}() 85 : 86 fHasValueBitmask(0), 87{{#propertyarray}} {{property.cppmembername}}({{property.cppdefaultvalue}}){{^islast}},{{/islast}} 88{{/propertyarray}}{ 89} 90 91 92{{cppname}}::~{{cppname}}() 93{ 94 Reset(); 95} 96 97 98void 99{{cppname}}::Reset() 100{ 101{{#propertyarray}}{{#property.isstring}} delete {{property.cppmembername}}; 102{{/property.isstring}}{{#property.isobject}} delete {{property.cppmembername}}; 103{{/property.isobject}}{{#property.isarray}} 104 if ({{property.cppmembername}} != NULL) { 105 for (int i = {{property.cppmembername}}->CountItems() - 1; i >= 0; i--) 106 delete {{property.cppmembername}}->ItemAt(i); 107 delete {{property.cppmembername}}; 108 } 109{{/property.isarray}} {{property.cppmembername}} = {{property.cppdefaultvalue}}; 110{{/propertyarray}} 111 fHasValueBitmask = 0; 112} 113 114{{#propertyarray}}{{#property.iscppscalartype}}{{property.cpptype}} 115{{cppobjectname}}::{{property.cppname}}() 116{ 117 return {{property.cppmembername}}; 118} 119 120 121void 122{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}} value) 123{ 124 fHasValueBitmask |= k{{property.cppname}}Bitmask; 125 {{property.cppmembername}} = value; 126} 127 128 129void 130{{cppobjectname}}::Set{{property.cppname}}Null() 131{ 132 fHasValueBitmask &= ~k{{property.cppname}}Bitmask; 133 {{property.cppmembername}} = {{property.cppdefaultvalue}}; 134} 135 136 137bool 138{{cppobjectname}}::{{property.cppname}}IsNull() 139{ 140 return 0 == (fHasValueBitmask & k{{property.cppname}}Bitmask); 141} 142 143{{/property.iscppscalartype}}{{#property.isarray}}void 144{{cppobjectname}}::AddTo{{property.cppname}}({{property.items.cpptype}}* value) 145{ 146 if ({{property.cppmembername}} == NULL) 147 {{property.cppmembername}} = new {{property.cpptype}}(); 148 {{property.cppmembername}}->AddItem(value); 149} 150 151 152void 153{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value) 154{ 155 if ({{property.cppmembername}} != NULL) { 156 delete {{property.cppmembername}}; 157 } 158 {{property.cppmembername}} = value; 159} 160 161 162int32 163{{cppobjectname}}::Count{{property.cppname}}() 164{ 165 if ({{property.cppmembername}} == NULL) 166 return 0; 167 return {{property.cppmembername}}->CountItems(); 168} 169 170 171{{property.items.cpptype}}* 172{{cppobjectname}}::{{property.cppname}}ItemAt(int32 index) 173{ 174 return {{property.cppmembername}}->ItemAt(index); 175} 176 177 178bool 179{{cppobjectname}}::{{property.cppname}}IsNull() 180{ 181 return {{property.cppmembername}} == NULL; 182} 183 184{{/property.isarray}}{{#property.iscppnonscalarnoncollectiontype}}{{property.cpptype}}* 185{{cppobjectname}}::{{property.cppname}}() 186{ 187 return {{property.cppmembername}}; 188} 189 190 191void 192{{cppobjectname}}::Set{{property.cppname}}({{property.cpptype}}* value) 193{ 194 {{property.cppmembername}} = value; 195} 196 197 198void 199{{cppobjectname}}::Set{{property.cppname}}Null() 200{ 201 if (!{{property.cppname}}IsNull()) { 202 delete {{property.cppmembername}}; 203 {{property.cppmembername}} = NULL; 204 } 205} 206 207 208bool 209{{cppobjectname}}::{{property.cppname}}IsNull() 210{ 211 return {{property.cppmembername}} == NULL; 212} 213 214{{/property.iscppnonscalarnoncollectiontype}} 215{{/propertyarray}} 216""" 217 218 219def write_models_for_schema(schema: dict[str, any], output_directory: str) -> None: 220 221 def write_model_object(obj: dict[str, any]) -> None: 222 cpp_name = obj["cppname"] 223 cpp_header_filename = os.path.join(output_directory, cpp_name + '.h') 224 cpp_implementation_filename = os.path.join(output_directory, cpp_name + '.cpp') 225 226 with open(cpp_header_filename, 'w') as cpp_h_file: 227 cpp_h_file.write(ustache.render( 228 HEADER_TEMPLATE, 229 obj, 230 escape= lambda x: x)) 231 232 with open(cpp_implementation_filename, 'w') as cpp_i_file: 233 cpp_i_file.write(ustache.render( 234 IMPLEMENTATION_TEMPLATE, 235 obj, 236 escape= lambda x: x)) 237 238 for obj in hdsjsonschemacommon.collect_all_objects(schema): 239 write_model_object(obj) 240 241 242def main(): 243 parser = argparse.ArgumentParser( 244 description='Convert JSON schema to Haiku C++ Models') 245 parser.add_argument( 246 '-i', '--inputfile', 247 required=True, 248 help='The input filename containing the JSON schema') 249 parser.add_argument( 250 '--outputdirectory', 251 help='The output directory where the C++ files should be written') 252 253 args = parser.parse_args() 254 255 output_directory = args.outputdirectory 256 257 if not output_directory: 258 output_directory = '.' 259 260 with open(args.inputfile) as inputfile: 261 schema = json.load(inputfile) 262 hdsjsonschemacommon.augment_schema(schema) 263 write_models_for_schema(schema, output_directory) 264 265 266if __name__ == "__main__": 267 main() 268 269