2015-06-21 23:42:29 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
/* Copyright (c) FIRST 2015. All Rights Reserved. */
|
|
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
#include "ntcore.h"
|
|
|
|
|
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
|
2015-06-22 00:25:59 -07:00
|
|
|
#include "llvm/StringExtras.h"
|
2015-06-25 23:12:49 -07:00
|
|
|
#include "base64.h"
|
|
|
|
|
#include "Storage.h"
|
2015-06-21 23:42:29 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
using namespace ntimpl;
|
|
|
|
|
|
2015-06-25 23:19:24 -07:00
|
|
|
static void WriteString(FILE* f, llvm::StringRef str) {
|
2015-06-25 22:57:43 -07:00
|
|
|
fputc('"', f);
|
|
|
|
|
for (unsigned int i = 0, e = str.size(); i != e; ++i) {
|
|
|
|
|
unsigned char c = str[i];
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
case '\\':
|
|
|
|
|
fputs("\\\\", f);
|
|
|
|
|
break;
|
|
|
|
|
case '\t':
|
|
|
|
|
fputs("\\t", f);
|
|
|
|
|
break;
|
|
|
|
|
case '\n':
|
|
|
|
|
fputs("\\n", f);
|
|
|
|
|
break;
|
|
|
|
|
case '"':
|
|
|
|
|
fputs("\\\"", f);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (std::isprint(c)) {
|
|
|
|
|
fputc(c, f);
|
|
|
|
|
break;
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
|
|
|
|
|
// Write out the escaped representation.
|
|
|
|
|
fputs("\\x", f);
|
|
|
|
|
fputc(llvm::hexdigit((c >> 4 & 0xF)), f);
|
|
|
|
|
fputc(llvm::hexdigit((c >> 0) & 0xF), f);
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
|
|
|
|
fputc('"', f);
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
const char* NT_SavePersistent(const char* filename) {
|
|
|
|
|
FILE* f = fopen(filename, "wt");
|
|
|
|
|
if (!f) return "could not open file";
|
|
|
|
|
|
|
|
|
|
fputs("[NetworkTables Storage 3.0]\n", f);
|
|
|
|
|
|
|
|
|
|
Storage& storage = Storage::GetInstance();
|
|
|
|
|
for (Storage::EntriesMap::const_iterator i = storage.entries.begin(),
|
|
|
|
|
end = storage.entries.end();
|
|
|
|
|
i != end; ++i) {
|
|
|
|
|
const StorageEntry& entry = i->getValue();
|
|
|
|
|
// only write persistent-flagged values
|
|
|
|
|
if ((entry.flags & NT_PERSISTENT) == 0) continue;
|
|
|
|
|
|
|
|
|
|
// type
|
|
|
|
|
const NT_Value& v = entry.value;
|
|
|
|
|
switch (v.type) {
|
|
|
|
|
case NT_BOOLEAN:
|
|
|
|
|
fputs("boolean ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE:
|
|
|
|
|
fputs("double ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_STRING:
|
|
|
|
|
fputs("string ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_RAW:
|
|
|
|
|
fputs("raw ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_BOOLEAN_ARRAY:
|
|
|
|
|
fputs("array boolean ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE_ARRAY:
|
|
|
|
|
fputs("array double ", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_STRING_ARRAY:
|
|
|
|
|
fputs("array string ", f);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2015-06-22 00:25:59 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
// name
|
2015-06-25 23:19:24 -07:00
|
|
|
WriteString(f, i->getKey());
|
2015-06-25 22:57:43 -07:00
|
|
|
|
|
|
|
|
// =
|
|
|
|
|
fputc('=', f);
|
|
|
|
|
|
|
|
|
|
// value
|
|
|
|
|
switch (v.type) {
|
|
|
|
|
case NT_BOOLEAN:
|
|
|
|
|
fputs(v.data.v_boolean ? "true" : "false", f);
|
|
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE:
|
|
|
|
|
fprintf(f, "%g", v.data.v_double);
|
|
|
|
|
break;
|
|
|
|
|
case NT_STRING:
|
2015-06-27 00:09:21 -07:00
|
|
|
WriteString(f, MakeStringRef(v.data.v_string));
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_RAW: {
|
2015-06-25 23:19:24 -07:00
|
|
|
char* buf = new char[Base64EncodeLen(v.data.v_raw.len)];
|
|
|
|
|
Base64Encode(buf,
|
2015-06-25 22:57:43 -07:00
|
|
|
reinterpret_cast<const unsigned char*>(v.data.v_raw.str),
|
|
|
|
|
v.data.v_raw.len);
|
|
|
|
|
fputs(buf, f);
|
|
|
|
|
delete[] buf;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case NT_BOOLEAN_ARRAY:
|
|
|
|
|
for (size_t i = 0; i < v.data.arr_boolean.size; ++i) {
|
|
|
|
|
fputs(v.data.arr_boolean.arr[i] ? "true" : "false", f);
|
|
|
|
|
if (i != (v.data.arr_boolean.size - 1)) fputc(',', f);
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE_ARRAY:
|
|
|
|
|
for (size_t i = 0; i < v.data.arr_double.size; ++i) {
|
|
|
|
|
fprintf(f, "%g", v.data.arr_double.arr[i]);
|
|
|
|
|
if (i != (v.data.arr_double.size - 1)) fputc(',', f);
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_STRING_ARRAY:
|
|
|
|
|
for (size_t i = 0; i < v.data.arr_double.size; ++i) {
|
2015-06-27 00:09:21 -07:00
|
|
|
WriteString(f, MakeStringRef(v.data.arr_string.arr[i]));
|
2015-06-25 22:57:43 -07:00
|
|
|
if (i != (v.data.arr_double.size - 1)) fputc(',', f);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
2015-06-22 00:25:59 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
// eol
|
|
|
|
|
fputc('\n', f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
return 0;
|
2015-06-21 23:42:29 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
const char* NT_LoadPersistent(const char* filename) {
|
|
|
|
|
FILE* f = fopen(filename, "rt");
|
|
|
|
|
if (!f) return "could not open file";
|
2015-06-22 00:25:59 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
fclose(f);
|
|
|
|
|
return 0;
|
2015-06-21 23:42:29 -07:00
|
|
|
}
|