-
Notifications
You must be signed in to change notification settings - Fork 24
Expand file tree
/
Copy pathcaosVM_resources.cpp
More file actions
499 lines (412 loc) · 13.1 KB
/
caosVM_resources.cpp
File metadata and controls
499 lines (412 loc) · 13.1 KB
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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
/*
* caosVM_resources.cpp
* openc2e
*
* Created by Alyssa Milburn on Sun Jun 13 2004.
* Copyright (c) 2004 Alyssa Milburn. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
*/
#include "caosVM.h"
#include "caosScript.h" // PRAY INJT
#include "World.h"
#include "Catalogue.h"
#include <boost/format.hpp>
#include <boost/filesystem/convenience.hpp>
namespace fs = boost::filesystem;
bool prayInstall(std::string name, unsigned int type, bool actually_install) {
std::string directory = world.praymanager.getResourceDir(type);
caos_assert(!directory.empty());
fs::path dir = fs::path(world.getUserDataDir()) / fs::path(directory);
if (!fs::exists(dir))
fs::create_directory(dir);
caos_assert(fs::exists(dir) && fs::is_directory(dir));
fs::path outputfile = dir / fs::path(name);
if (fs::exists(outputfile)) {
// TODO: update file if necessary? check it's not a directory :P
return true;
}
fs::path possiblefile = fs::path(directory) / fs::path(name);
if (!world.findFile(possiblefile.string()).empty()) {
// TODO: we need to return 'okay' if the file exists anywhere, but someone needs to work out update behaviour (see other comment above, also)
return true;
}
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
if (i == world.praymanager.blocks.end()) {
std::cout << "PRAY FILE: couldn't find block " << name << std::endl;
return false;
}
prayBlock *p = i->second;
if (p->type != "FILE") {
std::cout << "PRAY FILE: block " << name << " is " << p->type << " not FILE" << std::endl;
// TODO: correct behaviour? possibly not..
return false;
}
if (!actually_install) {
// TODO: work out if we've tested enough
return true;
}
p->load();
std::ofstream output(outputfile.string().c_str(), std::ios::binary);
output.write((char *)p->getBuffer(), p->getSize());
// p->unload();
if (type == 7) {
output.flush(); output.close();
// TODO: verify it is a catalogue file first, perhaps?
catalogue.addFile(outputfile);
}
return true;
}
int prayInstallDeps(std::string name, bool actually_install) {
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
caos_assert(i != world.praymanager.blocks.end());
prayBlock *p = i->second;
p->parseTags();
std::map<std::string, int>::iterator j = p->integerValues.find("Agent Type");
if (j == p->integerValues.end()) {
return -1;
}
// I have no idea what this is, so let's just error out when it's not zero, pending fix. - fuzzie
caos_assert(j->second == 0);
j = p->integerValues.find("Dependency Count");
if (j == p->integerValues.end()) {
return -2;
}
int nodeps = j->second; caos_assert(nodeps >= 0);
for (int z = 1; z <= nodeps; z++) {
std::string depcatname = boost::str(boost::format("Dependency Category %d") % z);
std::string depname = boost::str(boost::format("Dependency %d") % z);
j = p->integerValues.find(depcatname);
if (j == p->integerValues.end()) {
return (-2 - nodeps - z);
}
int depcat = j->second; caos_assert(depcat >= 0 && depcat <= 11);
std::map<std::string, std::string>::iterator k = p->stringValues.find(depname);
if (k == p->stringValues.end()) {
return (-2 - z);
}
std::string dep = k->second;
// TODO: CL docs say 2*count to 3*count is the category ID for that dependency being invalid
if (!prayInstall(dep, depcat, actually_install)) {
return z;
}
}
return 0;
}
//used by PRAY BACK, PRAY FORE, PRAY NEXT and PRAY PREV to implement their functionality
std::string findBlock(std::string type, std::string last, bool forward, bool loop) {
prayBlock *firstblock = 0, *currblock = 0;
bool foundblock = false;
if (world.praymanager.blocks.size() == 0) return ""; // We definitely can't find anything in that case!
// Where do we start?
std::map<std::string, prayBlock *>::iterator i;
if (forward)
i = world.praymanager.blocks.begin();
else {
i = world.praymanager.blocks.end();
i--;
}
// Loop through all the blocks.
while (true) {
if (i->second->type == type) {
currblock = i->second;
// Store the first block if we didn't already find one, for possible use later.
if (!firstblock)
firstblock = currblock;
// If this is the resource we want, grab it!
if (foundblock)
return currblock->name;
// If this is the resource we're looking for, make a note to grab the next one.
if (last == currblock->name)
foundblock = true;
}
// Step through the list. Break if we need to.
if (!forward && i == world.praymanager.blocks.begin()) break;
if (forward) i++; else i--;
if (forward && i == world.praymanager.blocks.end()) break;
}
if (foundblock && loop) return firstblock->name; // loop around to first-found block
else if (!foundblock && currblock) return firstblock->name; // default to first-found block (XXX this is in direct opposition to what CAOS docs say!)
return ""; // yarr, failure.
}
/**
PRAY AGTI (integer) resource (string) tag (string) default (integer)
%status maybe
using the specified resource, returns the integer value associated with the given tag,
or default if the tag doesn't exist
*/
void caosVM::v_PRAY_AGTI() {
VM_PARAM_INTEGER(_default)
VM_PARAM_STRING(tag)
VM_PARAM_STRING(resource)
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(resource);
caos_assert(i != world.praymanager.blocks.end());
prayBlock *p = i->second;
p->parseTags();
if (p->integerValues.find(tag) == p->integerValues.end())
result.setInt(_default);
else
result.setInt(p->integerValues[tag]);
}
/**
PRAY AGTS (string) resource (string) tag (string) default (string)
%status maybe
using the specified resource, returns the string value associated with the given tag,
or default if the tag doesn't exist
*/
void caosVM::v_PRAY_AGTS() {
VM_PARAM_STRING(_default)
VM_PARAM_STRING(tag)
VM_PARAM_STRING(resource)
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(resource);
caos_assert(i != world.praymanager.blocks.end());
prayBlock *p = i->second;
p->parseTags();
if (p->stringValues.find(tag) == p->stringValues.end())
result.setString(_default);
else
result.setString(p->stringValues[tag]);
}
/**
PRAY BACK (string) type (string) last (string)
%status maybe
returns the name of the resource of the specified type which is immediately previous to last
see PRAY PREV if you want to loop around
*/
void caosVM::v_PRAY_BACK() {
VM_PARAM_STRING(last)
VM_PARAM_STRING(type)
result.setString(findBlock(type, last, false, false));
}
/**
PRAY COUN (integer) type (string)
%status maybe
return the number of resources of the specified type available
*/
void caosVM::v_PRAY_COUN() {
VM_PARAM_STRING(type)
unsigned int count = 0;
for (std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.begin(); i != world.praymanager.blocks.end(); i++)
if (i->second->type == type)
count++;
result.setInt(count);
}
/**
PRAY DEPS (integer) name (string) install (integer)
%status maybe
*/
void caosVM::v_PRAY_DEPS() {
VM_PARAM_INTEGER(install)
VM_PARAM_STRING(name)
result.setInt(prayInstallDeps(name, install != 0));
}
/**
PRAY EXPO (integer) type (string)
%status stub
*/
void caosVM::v_PRAY_EXPO() {
VM_PARAM_STRING(type)
result.setInt(0); // TODO
}
/**
PRAY FILE (integer) name (integer) type (integer) install (integer)
%status maybe
install a file with given resource name and type
if install is 0, the install doesn't actually happen, it's just tested
returns 0 on success, 1 on failure
*/
void caosVM::v_PRAY_FILE() {
VM_PARAM_INTEGER(install)
VM_PARAM_INTEGER(type)
VM_PARAM_STRING(name)
if (prayInstall(name, type, (install != 0)))
result.setInt(0);
else
result.setInt(1);
}
/**
PRAY FORE (string) type (string) last (string)
%status maybe
returns the name of the resource of the specified type which is immediately after last
see PRAY NEXT if you want to loop around
*/
void caosVM::v_PRAY_FORE() {
VM_PARAM_STRING(last)
VM_PARAM_STRING(type)
result.setString(findBlock(type, last, true, false));
}
/**
PRAY GARB (command) force (integer)
%status stub
if force is 0, make the pray manager garbage-collect resources
otherwise, make the pray manager empty its cache entirely
recommended to be called after intensive PRAY usage, eg agent installation
*/
void caosVM::c_PRAY_GARB() {
VM_PARAM_INTEGER(force)
// TODO
}
/**
PRAY IMPO (integer) moniker (string) doit (integer) keepfile (integer)
%status stub
*/
void caosVM::v_PRAY_IMPO() {
VM_PARAM_INTEGER(keepfile)
VM_PARAM_INTEGER(doit)
VM_PARAM_STRING(moniker)
result.setInt(4); // TODO
}
/**
PRAY INJT (integer) name (string) install (integer) report (variable)
%status maybe
*/
void caosVM::v_PRAY_INJT() {
VM_PARAM_VARIABLE(report)
VM_PARAM_INTEGER(install)
VM_PARAM_STRING(name)
// Try installing the dependencies.
int r = prayInstallDeps(name, install != 0);
if (r != 0) {
result.setInt(-3);
report->setInt(r);
return;
}
// Now grab the relevant block..
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
caos_assert(i != world.praymanager.blocks.end());
prayBlock *p = i->second;
p->parseTags();
// .. grab the script count ..
std::map<std::string, int>::iterator j = p->integerValues.find("Script Count");
if (j == p->integerValues.end()) {
result.setInt(-3); // TODO: this isn't really a dependency fail, what do I do here?
return;
}
int noscripts = j->second; caos_assert(noscripts >= 0);
// .. and iterate over the scripts.
for (int z = 1; z <= noscripts; z++) {
// First, retrieve the script.
std::string scriptname = boost::str(boost::format("Script %d") % z);
std::map<std::string, std::string>::iterator k = p->stringValues.find(scriptname);
if (k == p->stringValues.end()) {
result.setInt(-1);
report->setString(scriptname);
return;
}
std::string script = k->second;
if (!install) continue;
// Then, execute it.
caosVM *vm = world.getVM(NULL);
try {
std::istringstream iss(script);
caosScript script(world.gametype, name + " - PRAY " + scriptname);
script.parse(iss);
script.installScripts();
vm->resetCore();
vm->runEntirely(script.installer);
} catch (std::exception &e) {
world.freeVM(vm);
result.setInt(-2);
report->setString(scriptname + " error: " + e.what());
std::cerr << "PRAY INJT caught exception trying to inject " << name << " - PRAY " << scriptname << ": " << e.what() << std::endl;
return;
}
world.freeVM(vm);
}
result.setInt(0);
}
/**
PRAY KILL (integer) resource (string)
%status stub
deletes from disk the file containing the given resource
returns 1 upon success, or 0 upon failure (typically no such resource)
*/
void caosVM::v_PRAY_KILL() {
VM_PARAM_STRING(resource)
result.setInt(0); // TODO
}
/**
PRAY MAKE (integer) journalspot (integer) journalname (string) prayspot (integer) name (string) report (variable)
%status stub
*/
void caosVM::v_PRAY_MAKE() {
VM_PARAM_VARIABLE(report)
VM_PARAM_STRING(name)
VM_PARAM_INTEGER(prayspot)
VM_PARAM_STRING(journalname)
VM_PARAM_INTEGER(journalspot)
result.setInt(1); // TODO
report->setString("hat u");
}
/**
NET: MAKE (integer) journalspot (integer) journalname (integer) user (string) report (variable)
%status stub
Networking is not supported in openc2e, so conveniently fails.
*/
void caosVM::v_NET_MAKE() {
VM_PARAM_VARIABLE(report)
VM_PARAM_STRING(user)
VM_PARAM_STRING(journalname)
VM_PARAM_INTEGER(journalspot)
result.setInt(1);
report->setString("Networking unsupported.");
}
/**
PRAY NEXT (string) type (string) last (string)
%status maybe
returns the name of the resource of the specified type which is immediately after last
see PRAY FORE if you don't want to loop around
*/
void caosVM::v_PRAY_NEXT() {
VM_PARAM_STRING(last)
VM_PARAM_STRING(type)
result.setString(findBlock(type, last, true, true));
}
/**
PRAY PREV (string) type (string) last (string)
%status maybe
returns the name of the resource of the specified type which is immediately previous to last
see PRAY BACK if you don't want to loop around
*/
void caosVM::v_PRAY_PREV() {
VM_PARAM_STRING(last)
VM_PARAM_STRING(type)
result.setString(findBlock(type, last, false, true));
}
/**
PRAY REFR (command)
%status maybe
make the pray manager check for deleted/new files in the resource directory
*/
void caosVM::c_PRAY_REFR() {
world.praymanager.update();
}
/**
PRAY TEST (integer) name (string)
%status maybe
*/
void caosVM::v_PRAY_TEST() {
VM_PARAM_STRING(name)
std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
if (i == world.praymanager.blocks.end())
result.setInt(0);
else {
prayBlock *p = i->second;
if (p->isLoaded())
result.setInt(1);
else if (p->isCompressed())
result.setInt(3);
else
result.setInt(2);
}
}
/* vim: set noet: */