File: json_verifier.lua

package info (click to toggle)
cataclysm-dda 0.C%2Bgit20190228.faafa3a-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 181,636 kB
  • sloc: cpp: 256,609; python: 2,621; makefile: 862; sh: 495; perl: 37; xml: 33
file content (175 lines) | stat: -rw-r--r-- 5,171 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
-- script to verify CDDA JSON(verifies all mods)
-- run this script with: lua lua/json_verifier.lua
--
-- requires luafilesystem to scan for files, installation instructions:
--  arch linux:   pacman -S lua-filesystem
--  debian linux: aptitude install liblua5.1-filesystem0
--  other linux distributions: search for "lua file system" in the
--                             package manager of your choice

local json = require("lua/dkjson")
local lfs = require("lfs")

local exit_code = 0

-- function to read a file completely into a string
function read_file(filename)
    local f = io.open(filename, "r")
    local content = f:read("*all")
    f:close()
    return content
end

decode_cache = {}

-- parse the JSON of an entire cataclysm file
function parse_cata_json(filename, handler)
    local root, pos, err
    if not decode_cache[filename] then
        local content = read_file(filename)

        root, pos, err = json.decode(content, 1, nil)
        decode_cache[filename] = root
    else
        root = decode_cache[filename]
    end

    if err then
        print("Error in ", filename ,":", err)
        os.exit(1)
    else
        -- top level should be a json array
        if type(root) ~= "table" then
            print("Wrong root element to JSON file ", filename, " :", type(root))
        end

        for _, entry in ipairs(root) do
            if not entry.type then
                print("Invalid entry type in ", filename, ": ", entry.type)
            end
            if handler[entry.type] then
                handler[entry.type](entry, filename)
            end
        end
    end
end

local definitions = {}
local material_definitions = {}
function load_item_definition(entry, filename)
    -- store that this item was defined
    definitions[entry.id] = true
end

-- define load_definition handlers
local load_definition = {}
local item_types = { "BOOK", "TOOL", "GUN", "GUNMOD", "TOOL_ARMOR", "ARMOR", "BIONIC_ITEM", "GENERIC", "AMMO", "CONTAINER", "COMESTIBLE", "VAR_VEH_PART" }
for _, item_type in ipairs(item_types) do
    load_definition[item_type] = load_item_definition
end

-- load definition handler for materials
function load_material_definition(entry, filename)
    -- store that this material was defined
    material_definitions[entry.ident] = true
end
load_definition.material = load_material_definition

local verify_handler = {}

function ensure_definition(id, filename, parent_id)
    if not definitions[id] then
        -- signify that something went wrong
        exit_code = 1

        print("Trying to access non-existent item id ", id, " in ", filename, "(", parent_id, ")")
    end
end

function ensure_material_definition(id, filename, parent_id)
    if not material_definitions[id] then
        -- signify that something went wrong
        exit_code = 1

        print("Trying to access non-existent material id ", id, " in ", filename, "(", parent_id, ")")
    end
end

verify_handler.recipe = function(entry, filename)
    ensure_definition(entry.result, filename, entry.result)
    for _, alternatives in ipairs(entry.components) do
        for _, item in ipairs(alternatives) do
            ensure_definition(item[1], filename, entry.result)
        end
    end
    if entry.tools then
        for _, alternatives in ipairs(entry.tools) do
            for _, item in ipairs(alternatives) do
                ensure_definition(item[1], filename, entry.result)
            end
        end
    end
end

function verify_item_definition(entry, filename)
    local materials
    if not entry.material or entry.material == "" then
        return
    elseif type(entry.material) == "string" then
        materials = { entry.material }
    elseif type(entry.material == "table") then
        materials = entry.material
    else
        exit_code = 1
        print("Invalid material for ", entry.id, " in ", filename)
    end

    for _, material in ipairs(materials) do
        ensure_material_definition(material, filename, entry.id)
    end
end

for _, item_type in ipairs(item_types) do
    verify_handler[item_type] = verify_item_definition
end


function string.endswith(mystr, myend)
   return myend=="" or string.sub(mystr,string.len(mystr)-string.len(myend)+1)==myend
end


function load_all_jsons_recursive(path, handler)
    for file in lfs.dir(path) do
        if file ~= "." and file ~= ".." then
            local f = path..'/'..file

            local attr = lfs.attributes(f)
            if attr.mode == "directory" then
                load_all_jsons_recursive(f, handler)
            elseif attr.mode == "file" and string.endswith(f, ".json") then
                parse_cata_json(f, handler)
            end
        end
    end
end

function load_all_jsons(handler)
    load_all_jsons_recursive("data/json", handler)
    load_all_jsons_recursive("data/mods", handler)
end

-- first load all item definitions
load_all_jsons(load_definition)

-- some hardcoded item definitions
definitions["cvd_machine"] = true
definitions["corpse"] = true
definitions["apparatus"] = true
definitions["toolset"] = true
definitions["fire"] = true

-- then verify recipes
load_all_jsons(verify_handler)

os.exit(exit_code)