00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include "xrb_datafilevalue.hpp"
00012
00013 #include <sstream>
00014
00015 #define THROW_STRING(x) \
00016 { \
00017 std::ostringstream out; \
00018 out << x; \
00019 throw out.str(); \
00020 }
00021
00022 namespace Xrb
00023 {
00024
00025 std::string const &DataFileElementTypeString (DataFileElementType data_file_element_type)
00026 {
00027 static std::string const s_data_file_element_type_string[DAT_COUNT] =
00028 {
00029 "DAT_BOOLEAN",
00030 "DAT_SINT32",
00031 "DAT_UINT32",
00032 "DAT_FLOAT",
00033 "DAT_CHARACTER",
00034 "DAT_STRING",
00035 "DAT_KEY_PAIR",
00036 "DAT_ARRAY",
00037 "DAT_STRUCTURE",
00038 "DAT_NO_TYPE"
00039 };
00040
00041 ASSERT1(data_file_element_type < DAT_COUNT);
00042 return s_data_file_element_type_string[data_file_element_type];
00043 }
00044
00045
00046
00047
00048
00049 bool DataFileValue::PathElementBoolean (std::string const &path) const throw (std::string)
00050 {
00051 DataFileBoolean const *value = dynamic_cast<DataFileBoolean const *>(PathElement(path));
00052 if (value == NULL)
00053 THROW_STRING("element is not a Boolean")
00054 return value->Value();
00055 }
00056
00057 Sint32 DataFileValue::PathElementSint32 (std::string const &path) const throw (std::string)
00058 {
00059 DataFileSint32 const *value = dynamic_cast<DataFileSint32 const *>(PathElement(path));
00060 if (value == NULL)
00061 THROW_STRING("element is not a Sint32")
00062 return value->Value();
00063 }
00064
00065 Uint32 DataFileValue::PathElementUint32 (std::string const &path) const throw (std::string)
00066 {
00067 DataFileUint32 const *value = dynamic_cast<DataFileUint32 const *>(PathElement(path));
00068 if (value == NULL)
00069 THROW_STRING("element is not a Uint32")
00070 return value->Value();
00071 }
00072
00073 Float DataFileValue::PathElementFloat (std::string const &path) const throw (std::string)
00074 {
00075 DataFileFloat const *value = dynamic_cast<DataFileFloat const *>(PathElement(path));
00076 if (value == NULL)
00077 THROW_STRING("element is not a Float")
00078 return value->Value();
00079 }
00080
00081 char DataFileValue::PathElementCharacter (std::string const &path) const throw (std::string)
00082 {
00083 DataFileCharacter const *value = dynamic_cast<DataFileCharacter const *>(PathElement(path));
00084 if (value == NULL)
00085 THROW_STRING("element is not a Character")
00086 return value->Value();
00087 }
00088
00089 std::string const &DataFileValue::PathElementString (std::string const &path) const throw (std::string)
00090 {
00091 DataFileString const *value = dynamic_cast<DataFileString const *>(PathElement(path));
00092 if (value == NULL)
00093 THROW_STRING("element is not a String")
00094 return value->Value();
00095 }
00096
00097 DataFileArray const *DataFileValue::PathElementArray (std::string const &path) const throw (std::string)
00098 {
00099 DataFileArray const *value = dynamic_cast<DataFileArray const *>(PathElement(path));
00100 if (value == NULL)
00101 THROW_STRING("element is not an Array")
00102 return value;
00103 }
00104
00105 DataFileStructure const *DataFileValue::PathElementStructure (std::string const &path) const throw (std::string)
00106 {
00107 DataFileStructure const *value = dynamic_cast<DataFileStructure const *>(PathElement(path));
00108 if (value == NULL)
00109 THROW_STRING("element is not a Structure")
00110 return value;
00111 }
00112
00113
00114
00115
00116
00117 DataFileLeafValue::~DataFileLeafValue () { }
00118
00119 DataFileValue const *DataFileLeafValue::SubpathElement (
00120 std::string const &path,
00121 Uint32 const start) const
00122 {
00123 ASSERT1(start <= path.length());
00124
00125 if (start < path.length())
00126 THROW_STRING("error: in path \"" << path << "\" - element type " <<
00127 DataFileElementTypeString(ElementType()) <<
00128 " can not have subelements (subpath \"" << &path[start] << "\")")
00129 return this;
00130 }
00131
00132
00133
00134
00135
00136 void DataFileBoolean::PrintAST (IndentFormatter &formatter) const
00137 {
00138 formatter.EndLine("DAT_BOOLEAN - %s", BOOL_TO_STRING(m_value));
00139 }
00140
00141
00142
00143
00144
00145 void DataFileSint32::PrintAST (IndentFormatter &formatter) const
00146 {
00147 formatter.EndLine("DAT_SINT32 - %+d", m_value);
00148 }
00149
00150
00151
00152
00153
00154 void DataFileUint32::PrintAST (IndentFormatter &formatter) const
00155 {
00156 formatter.EndLine("DAT_UINT32 - %u", m_value);
00157 }
00158
00159
00160
00161
00162
00163 void DataFileFloat::Sign (NumericSign const sign)
00164 {
00165 ASSERT1(sign == NEGATIVE || sign == POSITIVE);
00166 if (sign == NEGATIVE)
00167 m_value = -m_value;
00168 }
00169
00170 void DataFileFloat::PrintAST (IndentFormatter &formatter) const
00171 {
00172 formatter.EndLine("DAT_FLOAT - %g", m_value);
00173 }
00174
00175
00176
00177
00178
00179 void DataFileCharacter::PrintAST (IndentFormatter &formatter) const
00180 {
00181 formatter.EndLine("DAT_CHARACTER - '%c'", m_value);
00182 }
00183
00184
00185
00186
00187
00188 void DataFileString::Print (IndentFormatter &formatter) const
00189 {
00190 formatter.ContinueLine("%s", Util::StringLiteral(m_value).c_str());
00191 }
00192
00193 void DataFileString::PrintAST (IndentFormatter &formatter) const
00194 {
00195 formatter.EndLine("DAT_STRING - %s", Util::StringLiteral(m_value).c_str());
00196 }
00197
00198
00199
00200
00201
00202 void DataFileContainer::SetPathElementBoolean (std::string const &path, bool const value) throw(std::string)
00203 {
00204 SetSubpathElement(path, 0, new DataFileBoolean(value));
00205 }
00206
00207 void DataFileContainer::SetPathElementSint32 (std::string const &path, Sint32 const value) throw(std::string)
00208 {
00209 SetSubpathElement(path, 0, new DataFileSint32(value));
00210 }
00211
00212 void DataFileContainer::SetPathElementUint32 (std::string const &path, Uint32 const value) throw(std::string)
00213 {
00214 SetSubpathElement(path, 0, new DataFileUint32(value));
00215 }
00216
00217 void DataFileContainer::SetPathElementFloat (std::string const &path, Float const value) throw(std::string)
00218 {
00219 SetSubpathElement(path, 0, new DataFileFloat(value));
00220 }
00221
00222 void DataFileContainer::SetPathElementCharacter (std::string const &path, char const value) throw(std::string)
00223 {
00224 SetSubpathElement(path, 0, new DataFileCharacter(value));
00225 }
00226
00227 void DataFileContainer::SetPathElementString (std::string const &path, std::string const &value) throw(std::string)
00228 {
00229 SetSubpathElement(path, 0, new DataFileString(value));
00230 }
00231
00232 DataFileContainer::NodeType DataFileContainer::ParentElementNodeType (std::string const &path, Uint32 start) throw(std::string)
00233 {
00234 ASSERT1(start <= path.length());
00235
00236 if (start >= path.length())
00237 return NT_LEAF;
00238
00239 if (path[start] != '|')
00240 THROW_STRING("invalid subpath \"" << path.c_str() + start << "\" - expected '|' prefix")
00241
00242 ++start;
00243 if (start < path.length())
00244 {
00245 if (path[start] == '|')
00246 THROW_STRING("unexpected '|' character starting with subpath \"" << path.c_str() + start << "\"")
00247 if (path[start] >= '0' && path[start] <= '9')
00248 {
00249 do ++start; while (start < path.length() && path[start] >= '0' && path[start] <= '9');
00250 if (start >= path.length() || path[start] == '|')
00251 return NT_ARRAY;
00252 else
00253 THROW_STRING("invalid array index starting with subpath \"" << path.c_str() + start << "\"")
00254 }
00255 else if ((path[start] == '+' || path[start] == '$') &&
00256 (start+1 >= path.length() || path[start+1] == '|'))
00257 {
00258 return NT_ARRAY;
00259 }
00260 else
00261 return NT_STRUCTURE;
00262 }
00263 else
00264 THROW_STRING("path can not end with '|' character")
00265 }
00266
00267
00268
00269
00270
00271 void DataFileKeyPair::Print (IndentFormatter &formatter) const
00272 {
00273 ASSERT1(m_value != NULL);
00274 if (m_value->ElementType() == DAT_STRUCTURE)
00275 {
00276 formatter.PrintLine("%s\n{", m_key.c_str());
00277 formatter.Indent();
00278 m_value->Print(formatter);
00279 formatter.Unindent();
00280 formatter.BeginLine("}");
00281 }
00282 else if (m_value->ElementType() == DAT_ARRAY)
00283 {
00284 DataFileArray const *array = DStaticCast<DataFileArray const *>(m_value);
00285 ASSERT1(array != NULL);
00286 if (array->ShouldBeFormattedInline())
00287 formatter.BeginLine("%s ", m_key.c_str());
00288 else
00289 formatter.PrintLine("%s", m_key.c_str());
00290 m_value->Print(formatter);
00291 }
00292 else
00293 {
00294 formatter.BeginLine("%s ", m_key.c_str());
00295 m_value->Print(formatter);
00296 }
00297 }
00298
00299 void DataFileKeyPair::PrintAST (IndentFormatter &formatter) const
00300 {
00301 formatter.EndLine("DAT_KEY_PAIR");
00302 formatter.Indent();
00303 formatter.EndLine("key : %s", m_key.c_str());
00304 formatter.BeginLine("value: ");
00305 ASSERT1(m_value != NULL);
00306 m_value->PrintAST(formatter);
00307 formatter.Unindent();
00308 }
00309
00310 DataFileValue const *DataFileKeyPair::SubpathElement (
00311 std::string const &path,
00312 Uint32 const start) const
00313 {
00314 ASSERT1(start <= path.length());
00315
00316
00317
00318 if (start >= path.length())
00319 return Value();
00320
00321 if (path[start] != '|')
00322 THROW_STRING("invalid subpath \"" << &path[start] << "\" - expected '|' prefix")
00323
00324 return Value()->SubpathElement(path, start);
00325 }
00326
00327 void DataFileKeyPair::SetSubpathElement (
00328 std::string const &path,
00329 Uint32 const start,
00330 DataFileLeafValue *const value) throw(std::string)
00331 {
00332 ASSERT1(start <= path.length());
00333 ASSERT1(value != NULL);
00334
00335 switch (ParentElementNodeType(path, start))
00336 {
00337 case NT_LEAF:
00338 if (m_value != NULL)
00339 Delete(m_value);
00340 m_value = value;
00341 return;
00342
00343 case NT_ARRAY:
00344
00345 if (m_value != NULL && m_value->ElementType() == DAT_ARRAY)
00346 return DStaticCast<DataFileContainer *>(m_value)->SetSubpathElement(path, start, value);
00347
00348 else
00349 {
00350
00351 DataFileValue *array = new DataFileArray();
00352 try {
00353 static_cast<DataFileContainer *>(array)->SetSubpathElement(path, start, value);
00354 } catch (std::string const &exception) {
00355
00356 Delete(array);
00357 throw exception;
00358 }
00359
00360
00361 Delete(m_value);
00362 m_value = array;
00363 return;
00364 }
00365
00366 case NT_STRUCTURE:
00367
00368 if (m_value != NULL && m_value->ElementType() == DAT_STRUCTURE)
00369 return DStaticCast<DataFileContainer *>(m_value)->SetSubpathElement(path, start, value);
00370
00371 else
00372 {
00373
00374 DataFileValue *structure = new DataFileStructure();
00375 try {
00376 static_cast<DataFileContainer *>(structure)->SetSubpathElement(path, start, value);
00377 } catch (std::string const &exception) {
00378
00379 Delete(structure);
00380 throw exception;
00381 }
00382
00383
00384 Delete(m_value);
00385 m_value = structure;
00386 return;
00387 }
00388 }
00389 }
00390
00391
00392
00393
00394
00395 DataFileArray::~DataFileArray ()
00396 {
00397 for (ElementVector::iterator it = m_element_vector.begin(),
00398 it_end = m_element_vector.end();
00399 it != it_end;
00400 ++it)
00401 {
00402 DataFileValue const *value = *it;
00403 ASSERT1(value != NULL);
00404 Delete(value);
00405 }
00406 }
00407
00408 bool DataFileArray::ShouldBeFormattedInline () const
00409 {
00410 ElementVector::const_iterator it = m_element_vector.begin();
00411
00412
00413 if (it != m_element_vector.end())
00414 {
00415 DataFileValue const *value = *it;
00416 ASSERT1(value != NULL);
00417 ASSERT1(value->ElementType() != DAT_KEY_PAIR);
00418 return value->ElementType() != DAT_ARRAY && value->ElementType() != DAT_STRUCTURE;
00419 }
00420 else
00421
00422 return true;
00423 }
00424
00425 DataFileElementType DataFileArray::ArrayElementType () const
00426 {
00427 return m_element_vector.empty() ? DAT_NO_TYPE : m_element_vector[0]->ElementType();
00428 }
00429
00430 DataFileElementType DataFileArray::UltimateArrayElementType () const
00431 {
00432 if (m_element_vector.empty())
00433 return DAT_NO_TYPE;
00434
00435 if (m_element_vector[0]->ElementType() == DAT_ARRAY)
00436 return DStaticCast<DataFileArray const *>(m_element_vector[0])->UltimateArrayElementType();
00437
00438 return m_element_vector[0]->ElementType();
00439 }
00440
00441 Uint32 DataFileArray::DimensionCount () const
00442 {
00443 if (ArrayElementType() == DAT_ARRAY)
00444 return 1 + DStaticCast<DataFileArray const *>(m_element_vector[0])->DimensionCount();
00445 else
00446 return 1;
00447 }
00448
00449 void DataFileArray::AppendValue (DataFileValue *const value)
00450 {
00451 ASSERT1(value != NULL);
00452
00453
00454
00455 ElementVector::iterator it = m_element_vector.begin();
00456 if (it != m_element_vector.end())
00457 {
00458 DataFileValue const *first_element_value = *it;
00459 ASSERT1(first_element_value != NULL);
00460 if (value->ElementType() != first_element_value->ElementType())
00461 THROW_STRING("cannot add a " <<
00462 DataFileElementTypeString(value->ElementType()) <<
00463 " to an array with element type " <<
00464 DataFileElementTypeString(first_element_value->ElementType()))
00465 else if (value->ElementType() == DAT_ARRAY &&
00466 !DoesMatchDimensionAndType(
00467 DStaticCast<DataFileArray const *>(value),
00468 DStaticCast<DataFileArray const *>(first_element_value)))
00469 THROW_STRING("sibling elements in nested arrays must be of identical dimension and type")
00470 }
00471
00472
00473 m_element_vector.push_back(value);
00474 }
00475
00476 void DataFileArray::Print (IndentFormatter &formatter) const
00477 {
00478 bool inlined_array = ShouldBeFormattedInline();
00479
00480 if (inlined_array)
00481 formatter.BeginLine("[ ");
00482 else
00483 {
00484 formatter.PrintLine("[");
00485 formatter.Indent();
00486 }
00487
00488 ElementVector::const_iterator it_test;
00489 for (ElementVector::const_iterator it = m_element_vector.begin(),
00490 it_end = m_element_vector.end();
00491 it != it_end;
00492 ++it)
00493 {
00494 DataFileValue const *value = *it;
00495 ASSERT1(value != NULL);
00496 ASSERT1(value->ElementType() != DAT_KEY_PAIR);
00497
00498 if (value->ElementType() == DAT_STRUCTURE)
00499 {
00500 ASSERT1(!inlined_array);
00501 formatter.PrintLine("{");
00502 formatter.Indent();
00503 }
00504
00505 value->Print(formatter);
00506
00507 if (value->ElementType() == DAT_STRUCTURE)
00508 {
00509 ASSERT1(!inlined_array);
00510 formatter.Unindent();
00511 formatter.BeginLine("}");
00512 }
00513
00514 it_test = it;
00515 ++it_test;
00516 if (inlined_array)
00517 {
00518 if (it_test != it_end)
00519 formatter.ContinueLine(", ");
00520 else
00521 formatter.ContinueLine(" ");
00522 }
00523 else
00524 {
00525 if (it_test != it_end)
00526 formatter.EndLine(", ");
00527 else
00528 formatter.EndLine("");
00529 }
00530 }
00531
00532 if (inlined_array)
00533 formatter.ContinueLine("]");
00534 else
00535 {
00536 formatter.Unindent();
00537 formatter.BeginLine("]");
00538 }
00539 }
00540
00541 void DataFileArray::PrintAST (IndentFormatter &formatter) const
00542 {
00543 formatter.EndLine(
00544 "DAT_ARRAY - %u dimensions - %u element(s) of type %s",
00545 DimensionCount(),
00546 m_element_vector.size(),
00547 DataFileElementTypeString(ArrayElementType()).c_str());
00548 formatter.Indent();
00549 for (Uint32 i = 0; i < m_element_vector.size(); ++i)
00550 {
00551 formatter.BeginLine("[%3u]: ", i);
00552 ASSERT1(m_element_vector[i] != NULL);
00553 m_element_vector[i]->PrintAST(formatter);
00554 }
00555 formatter.Unindent();
00556 }
00557
00558 DataFileValue const *DataFileArray::SubpathElement (
00559 std::string const &path,
00560 Uint32 start) const
00561 {
00562 ASSERT1(start <= path.length());
00563
00564
00565
00566 if (start >= path.length())
00567 return this;
00568
00569 if (path[start] != '|')
00570 THROW_STRING("invalid subpath \"" << &path[start] << "\" - expected '|' prefix")
00571
00572 ++start;
00573 Uint32 key_delim = Min(path.length(), path.find_first_of("|", start));
00574
00575 if (start == key_delim)
00576 THROW_STRING("missing array index")
00577
00578 Uint32 array_index = 0;
00579 for (Uint32 i = start; i < key_delim; ++i)
00580 {
00581 if (path[i] >= '0' && path[i] <= '9')
00582 array_index = 10 * array_index + path[i] - '0';
00583 else
00584 THROW_STRING("invalid array index \"" << path.substr(start, key_delim-start) << "\"")
00585 }
00586
00587 if (array_index >= m_element_vector.size())
00588 THROW_STRING("out of bounds array index \"" << path.substr(start, key_delim-start) << "\"")
00589
00590 ASSERT1(key_delim < UINT32_UPPER_BOUND);
00591 return m_element_vector[array_index]->SubpathElement(path, key_delim);
00592 }
00593
00594 void DataFileArray::SetSubpathElement (
00595 std::string const &path,
00596 Uint32 start,
00597 DataFileLeafValue *const value) throw(std::string)
00598 {
00599 ASSERT1(start <= path.length());
00600 ASSERT1(value != NULL);
00601
00602 if (start >= path.length())
00603 THROW_STRING("can't assign a value to an array itself - subpath \"" << path.c_str() + start << "\"")
00604
00605 if (path[start] != '|')
00606 THROW_STRING("invalid subpath \"" << path.c_str() + start << "\" - expected '|' prefix")
00607
00608 ASSERT1(ParentElementNodeType(path, start) == NT_ARRAY);
00609
00610 ++start;
00611 Uint32 key_delim = Min(path.length(), path.find_first_of("|", start));
00612 NodeType element_type = ParentElementNodeType(path, key_delim);
00613
00614
00615 Uint32 array_index = UINT32_UPPER_BOUND;
00616 bool create_new_element = false;
00617 if (key_delim-start == 1 && (path[start] == '+' || path[start] == '$'))
00618 {
00619 if (path[start] == '+')
00620 create_new_element = true;
00621 else if (path[start] == '$')
00622 {
00623 if (m_element_vector.empty())
00624 THROW_STRING("$ can not be used on array with no elements - subpath \"" << path.c_str() + start << "\"")
00625 array_index = m_element_vector.size()-1;
00626 }
00627 else
00628 ASSERT1(false && "this should never happen");
00629 }
00630
00631 else
00632 {
00633 Uint32 i = start;
00634 array_index = 0;
00635 char c = path[i];
00636 while (i < key_delim && (c = path[i], c >= '0' && c <= '9'))
00637 {
00638
00639 if (array_index > 429496729 || (array_index == 429496729 && c > '5'))
00640 {
00641 array_index = UINT32_UPPER_BOUND;
00642 break;
00643 }
00644 else
00645 array_index = 10 * array_index + (c - '0');
00646 ++i;
00647 }
00648 if (c < '0' || c > '9')
00649 THROW_STRING("invalid array index in subpath \"" << path.c_str() + start << "\"")
00650 }
00651
00652
00653 ASSERT1(m_element_vector.size() < UINT32_UPPER_BOUND);
00654
00655 if (create_new_element)
00656 {
00657 DataFileValue *element;
00658 switch (element_type)
00659 {
00660 case NT_LEAF:
00661 element = value;
00662 break;
00663
00664 case NT_ARRAY:
00665 element = new DataFileArray();
00666 try {
00667 static_cast<DataFileContainer *>(element)->SetSubpathElement(path, key_delim, value);
00668 } catch (std::string const &exception) {
00669 Delete(element);
00670 throw exception;
00671 }
00672 break;
00673
00674 case NT_STRUCTURE:
00675 element = new DataFileStructure();
00676 try {
00677 static_cast<DataFileContainer *>(element)->SetSubpathElement(path, key_delim, value);
00678 } catch (std::string const &exception) {
00679 Delete(element);
00680 throw exception;
00681 }
00682 break;
00683 }
00684
00685
00686 if (!m_element_vector.empty())
00687 {
00688 DataFileValue const *first_element = m_element_vector[0];
00689 ASSERT1(first_element != NULL);
00690 if (element->ElementType() != first_element->ElementType())
00691 {
00692 std::ostringstream out;
00693 out << "mismatch: array element type " << DataFileElementTypeString(first_element->ElementType())
00694 << ", assignment type " << DataFileElementTypeString(element->ElementType());
00695 Delete(element);
00696 throw out.str();
00697 }
00698 else if (element->ElementType() == DAT_ARRAY &&
00699 (DStaticCast<DataFileArray const *>(first_element)->DimensionCount() !=
00700 DStaticCast<DataFileArray const *>(element)->DimensionCount()
00701 ||
00702 static_cast<DataFileArray const *>(first_element)->UltimateArrayElementType() !=
00703 static_cast<DataFileArray const *>(element)->UltimateArrayElementType()))
00704 {
00705 std::ostringstream out;
00706 out << "mismatch: array depth " << static_cast<DataFileArray const *>(first_element)->DimensionCount()
00707 << "/type " << DataFileElementTypeString(static_cast<DataFileArray const *>(first_element)->UltimateArrayElementType())
00708 << ", assignment depth " << static_cast<DataFileArray const *>(element)->DimensionCount()
00709 << "/type " << DataFileElementTypeString(static_cast<DataFileArray const *>(element)->UltimateArrayElementType());
00710 Delete(element);
00711 throw out.str();
00712 }
00713 }
00714
00715 m_element_vector.push_back(element);
00716 return;
00717 }
00718 else if (array_index >= m_element_vector.size())
00719 THROW_STRING("array index " << array_index << " out of bounds in subpath \"" << path.c_str() + start << "\"")
00720 else
00721 {
00722 ASSERT1(element_type == NT_LEAF || element_type == NT_ARRAY || element_type == NT_STRUCTURE);
00723 ASSERT1(!m_element_vector.empty());
00724 ASSERT1(m_element_vector[array_index] != NULL);
00725 DataFileValue *&element = m_element_vector[array_index];
00726
00727 if ((element_type == NT_LEAF && value->ElementType() != element->ElementType())
00728 ||
00729 (element_type == NT_ARRAY && element->ElementType() != DAT_ARRAY)
00730 ||
00731 (element_type == NT_STRUCTURE && element->ElementType() != DAT_STRUCTURE))
00732 {
00733 DataFileElementType assignment_type = DAT_NO_TYPE;
00734 if (element_type == NT_LEAF)
00735 assignment_type = value->ElementType();
00736 else if (element_type == NT_ARRAY)
00737 assignment_type = DAT_ARRAY;
00738 else if (element_type == NT_STRUCTURE)
00739 assignment_type = DAT_STRUCTURE;
00740
00741 ASSERT1(assignment_type != DAT_NO_TYPE);
00742 THROW_STRING("mismatch: array element type " << DataFileElementTypeString(element->ElementType()) << ", assignment type " << DataFileElementTypeString(assignment_type))
00743 }
00744
00745 if (element_type == NT_LEAF)
00746 {
00747 Delete(element);
00748 element = value;
00749 return;
00750 }
00751 else if (element_type == NT_ARRAY || element_type == NT_STRUCTURE)
00752 {
00753 return DStaticCast<DataFileContainer *>(element)->SetSubpathElement(path, key_delim, value);
00754 }
00755 else
00756 {
00757 ASSERT1(false && "this should never happen");
00758 return;
00759 }
00760 }
00761 }
00762
00763 std::string DataFileArray::DimensionAndTypeString () const
00764 {
00765 std::ostringstream out;
00766
00767 out << DataFileElementTypeString(UltimateArrayElementType());
00768
00769 DataFileValue const *value = this;
00770 while (value != NULL && value->ElementType() == DAT_ARRAY)
00771 {
00772 out << '[' << DStaticCast<DataFileArray const *>(value)->m_element_vector.size() << ']';
00773 if (DStaticCast<DataFileArray const *>(value)->m_element_vector.empty())
00774 value = NULL;
00775 else
00776 value = DStaticCast<DataFileArray const *>(value)->m_element_vector[0];
00777 }
00778
00779 return out.str();
00780 }
00781
00782 bool DataFileArray::DoesMatchDimensionAndType (
00783 DataFileArray const *const array0,
00784 DataFileArray const *const array1)
00785 {
00786 ASSERT1(array0 != NULL);
00787 ASSERT1(array1 != NULL);
00788
00789 if (array0->m_element_vector.size() != array1->m_element_vector.size())
00790 return false;
00791
00792 if (array0->m_element_vector.empty())
00793 return true;
00794
00795 if (array0->m_element_vector[0]->ElementType() != array1->m_element_vector[0]->ElementType())
00796 return false;
00797
00798 if (array0->m_element_vector[0]->ElementType() == DAT_ARRAY)
00799 return
00800 DoesMatchDimensionAndType(
00801 DStaticCast<DataFileArray const *>(array0->m_element_vector[0]),
00802 DStaticCast<DataFileArray const *>(array1->m_element_vector[0]));
00803
00804 return true;
00805 }
00806
00807
00808
00809
00810
00811 DataFileStructure::~DataFileStructure ()
00812 {
00813 for (MemberMap::iterator it = m_member_map.begin(),
00814 it_end = m_member_map.end();
00815 it != it_end;
00816 ++it)
00817 {
00818 DataFileKeyPair const *key_pair = it->second;
00819 ASSERT1(key_pair != NULL);
00820 Delete(key_pair);
00821 }
00822 }
00823
00824 DataFileValue const *DataFileStructure::Value (std::string const &key) const
00825 {
00826 ASSERT1(key.length() > 0);
00827 MemberMap::const_iterator it = m_member_map.find(key);
00828 if (it == m_member_map.end())
00829 return NULL;
00830 else
00831 return it->second->Value();
00832 }
00833
00834 void DataFileStructure::AddKeyPair (std::string const &key, DataFileValue *value)
00835 {
00836 ASSERT1(!key.empty());
00837 ASSERT1(value != NULL);
00838
00839 if (!IsValidKey(key))
00840 THROW_STRING("key \"" << key << "\" contains invalid characters")
00841
00842 if (m_member_map.find(key) == m_member_map.end())
00843 m_member_map[key] = new DataFileKeyPair(key, value);
00844 else
00845 THROW_STRING("collision with key \"" << key << "\"")
00846 }
00847
00848 void DataFileStructure::AddKeyPair (DataFileKeyPair *const key_pair)
00849 {
00850 ASSERT1(key_pair != NULL);
00851 ASSERT1(!key_pair->GetKey().empty());
00852 ASSERT1(key_pair->Value() != NULL);
00853
00854 if (!IsValidKey(key_pair->GetKey()))
00855 THROW_STRING("key \"" << key_pair->GetKey() << "\" contains invalid characters")
00856
00857 if (m_member_map.find(key_pair->GetKey()) == m_member_map.end())
00858 m_member_map[key_pair->GetKey()] = key_pair;
00859 else
00860 THROW_STRING("collision with key \"" << key_pair->GetKey() << "\"")
00861 }
00862
00863 void DataFileStructure::Print (IndentFormatter &formatter) const
00864 {
00865 for (MemberMap::const_iterator it = m_member_map.begin(),
00866 it_end = m_member_map.end();
00867 it != it_end;
00868 ++it)
00869 {
00870 DataFileKeyPair const *key_pair = it->second;
00871 ASSERT1(key_pair != NULL);
00872 key_pair->Print(formatter);
00873 formatter.EndLine(";");
00874 }
00875 }
00876
00877 void DataFileStructure::PrintAST (IndentFormatter &formatter) const
00878 {
00879 formatter.EndLine("DAT_STRUCTURE - %u element(s)", m_member_map.size());
00880 formatter.Indent();
00881 for (MemberMap::const_iterator it = m_member_map.begin(),
00882 it_end = m_member_map.end();
00883 it != it_end;
00884 ++it)
00885 {
00886 DataFileKeyPair const *key_pair = it->second;
00887 ASSERT1(key_pair != NULL);
00888 key_pair->PrintAST(formatter);
00889 }
00890 formatter.Unindent();
00891 }
00892
00893 DataFileValue const *DataFileStructure::SubpathElement (
00894 std::string const &path,
00895 Uint32 start) const
00896 {
00897 ASSERT1(start <= path.length());
00898
00899
00900
00901 if (start >= path.length())
00902 return this;
00903
00904 if (path[start] != '|')
00905 THROW_STRING("invalid subpath \"" << &path[start] << "\" - expected '|' prefix")
00906
00907 ++start;
00908 Uint32 key_delim = Min(path.length(), path.find_first_of("|", start));
00909 std::string key(path.substr(start, key_delim-start));
00910 MemberMap::const_iterator it = m_member_map.find(key);
00911 if (it == m_member_map.end())
00912 THROW_STRING("unmatched element \"" << key << "\"")
00913 else
00914 {
00915 ASSERT1(key_delim < UINT32_UPPER_BOUND);
00916 return it->second->Value()->SubpathElement(path, key_delim);
00917 }
00918 }
00919
00920 void DataFileStructure::SetSubpathElement (
00921 std::string const &path,
00922 Uint32 start,
00923 DataFileLeafValue *const value) throw(std::string)
00924 {
00925 ASSERT1(start <= path.length());
00926 ASSERT1(value != NULL);
00927
00928 if (start >= path.length())
00929 THROW_STRING("can't assign a value to a structure itself")
00930
00931 if (path[start] != '|')
00932 THROW_STRING("invalid subpath \"" << path.c_str() + start << "\" - expected '|' prefix")
00933
00934 ASSERT1(ParentElementNodeType(path, start) == NT_STRUCTURE);
00935
00936 ++start;
00937 Uint32 key_delim = Min(path.length(), path.find_first_of("|", start));
00938 ASSERT1(key_delim < UINT32_UPPER_BOUND);
00939
00940 std::string key(path.substr(start, key_delim-start));
00941 if (!IsValidKey(key))
00942 THROW_STRING("invalid key \"" << key << "\"")
00943
00944 MemberMap::const_iterator it = m_member_map.find(key);
00945 if (it == m_member_map.end())
00946 {
00947 DataFileKeyPair *key_pair = new DataFileKeyPair(key, NULL);
00948 try {
00949 static_cast<DataFileContainer *>(key_pair)->SetSubpathElement(path, key_delim, value);
00950 } catch (std::string const &exception) {
00951 Delete(key_pair);
00952 throw exception;
00953 }
00954 m_member_map[key] = key_pair;
00955 return;
00956 }
00957 else
00958 return static_cast<DataFileContainer *>(it->second)->SetSubpathElement(path, key_delim, value);
00959 }
00960
00961 bool DataFileStructure::IsValidKey (std::string const &key)
00962 {
00963 char c = key[0];
00964 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_')
00965 return false;
00966
00967 for (Uint32 i = 1; i < key.length(); ++i)
00968 {
00969 c = key[i];
00970 if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z') && c != '_' && (c < '0' || c > '9'))
00971 return false;
00972 }
00973
00974 return true;
00975 }
00976
00977 }
00978