+ if ((bufpos - buf) + sizeof(std::string *) <= len)
+ *(std::string **)bufpos = str;
+ bufpos += sizeof(std::string *);
+ strs_alloced.push_back(str);
+
+ s = *snext ? snext + 1 : NULL;
+ break;
+ case 'v':
+ while (*s == ' ' || *s == '\t')
+ s++;
+ if (*s++ != '(') //error, expected vector
+ goto fail;
+
+ if (width == 2) {
+ bufpos += PADDING(bufpos, v2f);
+
+ if ((bufpos - buf) + sizeof(v2f) <= len) {
+ v2f *v = (v2f *)bufpos;
+ v->X = strtof(s, &s);
+ s++;
+ v->Y = strtof(s, &s);
+ }
+
+ bufpos += sizeof(v2f);
+ } else if (width == 3) {
+ bufpos += PADDING(bufpos, v3f);
+ if ((bufpos - buf) + sizeof(v3f) <= len) {
+ v3f *v = (v3f *)bufpos;
+ v->X = strtof(s, &s);
+ s++;
+ v->Y = strtof(s, &s);
+ s++;
+ v->Z = strtof(s, &s);
+ }
+
+ bufpos += sizeof(v3f);
+ }
+ s = strchr(s, ',');
+ break;
+ default: //error, invalid format specifier
+ goto fail;
+ }
+
+ if (s && *s == ',')
+ s++;
+
+ if ((size_t)(bufpos - buf) > len) //error, buffer too small
+ goto fail;
+ }
+
+ if (f && *f) { //error, mismatched number of fields and values
+fail:
+ for (size_t i = 0; i != strs_alloced.size(); i++)
+ delete strs_alloced[i];
+ delete[] buf;
+ return false;
+ }
+
+ memcpy(out, buf, olen);
+ delete[] buf;
+ return true;
+}
+
+// Casts *buf to a signed or unsigned fixed-width integer of 'w' width
+#define SIGN_CAST(w, buf) (is_unsigned ? *((u##w *) buf) : *((s##w *) buf))
+
+bool serializeStructToString(std::string *out,
+ std::string format, void *value)
+{
+ std::ostringstream os;
+ std::string str;
+ char *f;
+ size_t strpos;
+
+ char *bufpos = (char *) value;
+ char *fmtpos, *fmt = &format[0];
+ while ((f = strtok_r(fmt, ",", &fmtpos))) {
+ fmt = NULL;
+ bool is_unsigned = false;
+ int width = 0;
+ char valtype = *f;
+
+ width = (int)strtol(f + 1, &f, 10);
+ if (width && valtype == 's')
+ valtype = 'i';
+
+ switch (valtype) {
+ case 'u':
+ is_unsigned = true;
+ /* FALLTHROUGH */
+ case 'i':
+ if (width == 16) {
+ bufpos += PADDING(bufpos, u16);
+ os << SIGN_CAST(16, bufpos);
+ bufpos += sizeof(u16);
+ } else if (width == 32) {
+ bufpos += PADDING(bufpos, u32);
+ os << SIGN_CAST(32, bufpos);
+ bufpos += sizeof(u32);
+ } else if (width == 64) {
+ bufpos += PADDING(bufpos, u64);
+ os << SIGN_CAST(64, bufpos);
+ bufpos += sizeof(u64);
+ }
+ break;
+ case 'b':
+ bufpos += PADDING(bufpos, bool);
+ os << std::boolalpha << *((bool *) bufpos);
+ bufpos += sizeof(bool);
+ break;
+ case 'f':
+ bufpos += PADDING(bufpos, float);
+ os << *((float *) bufpos);
+ bufpos += sizeof(float);
+ break;
+ case 's':
+ bufpos += PADDING(bufpos, std::string *);
+ str = **((std::string **) bufpos);
+
+ strpos = 0;
+ while ((strpos = str.find('"', strpos)) != std::string::npos) {
+ str.insert(strpos, 1, '\\');
+ strpos += 2;
+ }
+
+ os << str;
+ bufpos += sizeof(std::string *);
+ break;
+ case 'v':
+ if (width == 2) {
+ bufpos += PADDING(bufpos, v2f);
+ v2f *v = (v2f *) bufpos;
+ os << '(' << v->X << ", " << v->Y << ')';
+ bufpos += sizeof(v2f);
+ } else {
+ bufpos += PADDING(bufpos, v3f);
+ v3f *v = (v3f *) bufpos;
+ os << '(' << v->X << ", " << v->Y << ", " << v->Z << ')';
+ bufpos += sizeof(v3f);
+ }
+ break;
+ default:
+ return false;
+ }
+ os << ", ";
+ }
+ *out = os.str();
+
+ // Trim off the trailing comma and space
+ if (out->size() >= 2)
+ out->resize(out->size() - 2);
+
+ return true;
+}
+
+#undef SIGN_CAST
+
+////
+//// Other
+////
+
+std::string serializeHexString(const std::string &data, bool insert_spaces)
+{
+ std::string result;
+ result.reserve(data.size() * (2 + insert_spaces));
+
+ static const char hex_chars[] = "0123456789abcdef";
+
+ const size_t len = data.size();
+ for (size_t i = 0; i != len; i++) {
+ u8 byte = data[i];
+ result.push_back(hex_chars[(byte >> 4) & 0x0F]);
+ result.push_back(hex_chars[(byte >> 0) & 0x0F]);
+ if (insert_spaces && i != len - 1)
+ result.push_back(' ');
+ }
+
+ return result;
+}