Jamoma API  0.6.0.a19
TTAddressBase.cpp
1 /*
2  * TTAddressBase
3  * Copyright © 2011, Théo de la Hogue
4  *
5  * License: This code is licensed under the terms of the "New BSD License"
6  * http://creativecommons.org/licenses/BSD/
7  */
8 
9 #ifndef DISABLE_NODELIB
10 
11 #include "TTFoundationAPI.h"
12 
13 #if BOOST_REGEX
14 #include <boost/regex.hpp>
15 using namespace boost;
16 #else
17 #include <regex>
18 using namespace std;
19 #endif
20 
21 TTFOUNDATION_EXPORT TTRegex* ttRegexForDirectory = NULL;
22 TTFOUNDATION_EXPORT TTRegex* ttRegexForAttribute = NULL;
23 TTFOUNDATION_EXPORT TTRegex* ttRegexForParent = NULL;
24 TTFOUNDATION_EXPORT TTRegex* ttRegexForInstance = NULL;
25 
26 TTAddressBase::TTAddressBase(const TTString& newAddressString, TTPtrSizedInt newAddressTableId, TTInt32 newId) :
27  TTSymbolBase(newAddressString, newAddressTableId, newId),
28  directory(NO_DIRECTORY),
29  parent(NO_PARENT.getBasePointer()),
30  name(NO_NAME),
31  instance(NO_INSTANCE),
32  attribute(NO_ATTRIBUTE),
33  parsed(NO)
34 {
35  this->init(newAddressString, newAddressTableId, newId);
36 }
37 
39 {
40  ;
41 }
42 
44 {
45  if (!parsed)
46  parse();
47  return directory;
48 }
49 
51 {
52  if (!parsed)
53  parse();
54  return parent;
55 }
56 
58 {
59  if (!parsed)
60  parse();
61  return name;
62 }
63 
65 {
66  if (!parsed)
67  parse();
68  return instance;
69 }
70 
72 {
73  if (!parsed)
74  parse();
75  return this->attribute;
76 }
77 
79 {
80  if (!parsed)
81  parse();
82  return type;
83 }
84 
86 {
87  TTSymbol nameInstanceSymbol = this->getName();
88  TTString nameInstance = nameInstanceSymbol.c_str();
89 
90  if (this->getInstance() != NO_INSTANCE) {
91  nameInstance += C_INSTANCE;
92  nameInstance += this->getInstance().c_str();
93  }
94 
95  return TTSymbol(nameInstance);
96 }
97 
99 {
100  if (!parsed)
101  parse();
102 
103  return this->normalized;
104 }
105 
107 {
108  if (!parsed)
109  parse();
110 
111  if (attribute != NO_ATTRIBUTE)
112  return edit(this->directory, this->parent, this->name, this->instance, NO_ATTRIBUTE);
113  else
114  return this;
115 }
116 
118 {
119  if (!parsed)
120  parse();
121 
122  return edit(this->directory, this->parent, this->name, this->instance, anAttribute);
123 }
124 
126 {
127  if (*toAppend == kTTAdrsEmpty || *toAppend == kTTAdrsRoot)
128  return this;
129 
130  else if (this == kTTAdrsEmpty)
131  return toAppend;
132 
133  TTString tmp = this->getCString();
134 
135  // insert a / if the first part is not the root and the address to append is not absolute
136  if (this->normalize() != kTTAdrsRoot.getBasePointer() && toAppend->getType() != kAddressAbsolute && toAppend->getName() != NO_NAME) {
137  tmp += C_SEPARATOR;
138  tmp += toAppend->getCString();
139  }
140 
141  // just keep the the second part if the first part is the root and the address to append is absolute
142  else if (this->normalize() == kTTAdrsRoot.getBasePointer() && toAppend->getType() == kAddressAbsolute)
143  return toAppend;
144 
145  // else append the address
146  else
147  tmp += toAppend->getCString();
148 
149  return (TTAddressBase*)gTTAddressTable.lookup(tmp.data()); // TTADRS(tmp.data());
150 }
151 
153 {
154  if (!parsed)
155  parse();
156  return edit(this->directory, this->parent, this->name, anInstance, this->attribute);
157 }
158 
159 
161  const TTAddressBase* newParent,
162  const TTSymbol& newName,
163  const TTSymbol& newInstance,
164  const TTSymbol& newAttribute)
165 {
166  TTString address;
167 
168  if (newDirectory != NO_DIRECTORY) {
169  address = newDirectory.c_str();
170  address += ":"; // don't put :/ here because the parent or the name should have one.
171  }
172 
173  if (newParent != NO_PARENT.getBasePointer()) {
174  if (newDirectory == NO_DIRECTORY)
175  address = newParent->normalized->getCString();
176  else
177  address += newParent->normalized->getCString();
178  }
179 
180  if(newName != NO_NAME){
181  if((newName != S_SEPARATOR) && (newParent != kTTAdrsRoot.getBasePointer()))
182  if (newDirectory != NO_DIRECTORY || newParent != NO_PARENT.getBasePointer())
183  address += S_SEPARATOR.c_str();
184  address += newName.c_str();
185  }
186 
187  if (newInstance != NO_INSTANCE) {
188  address += S_INSTANCE.c_str();
189  address += newInstance.c_str();
190  }
191 
192  if(newAttribute != NO_ATTRIBUTE){
193  address += S_ATTRIBUTE.c_str();
194  address += newAttribute.c_str();
195  }
196 
197  return (TTAddressBase*)gTTAddressTable.lookup(address);
198 }
199 
200 TTErr TTAddressBase::parse()
201 {
202  // "directory:/parent/address/name.instance:attribute" parsing
203 
204  // Empty case :
205  if (*this == *kTTAdrsEmpty.getBasePointer()) {
206  this->directory = NO_DIRECTORY;
207  this->parent = NO_PARENT.getBasePointer();
208  this->name = NO_NAME;
209  this->instance = NO_INSTANCE;
210  this->attribute = NO_ATTRIBUTE;
211  this->type = kAddressRelative;
212  this->parsed = YES;
213  this->normalized = this;
214  return kTTErrNone;
215  }
216 
217  // Root case :
218  if (*this == *kTTAdrsRoot.getBasePointer()) {
219  this->directory = NO_DIRECTORY;
220  this->parent = NO_PARENT.getBasePointer();
221  this->name = S_SEPARATOR;
222  this->instance = NO_INSTANCE;
223  this->attribute = NO_ATTRIBUTE;
224  this->type = kAddressAbsolute;
225  this->parsed = YES;
226  this->normalized = this;
227  return kTTErrNone;
228  }
229 
230  // All other case needs a regex parsing
231  TTString s_toParse = this->getCString();
232  TTString s_before;
233  TTString s_after;
234  TTString s_directory;
235  TTString s_parent;
236  TTString s_name;
237  TTString s_instance;
238  TTString s_attribute;
239 
240  // warning : addresses with special regex characters (like [, {) that could be problematic
241  // TODO : rewrite the parsing without regex because we want to use those special characters !
242  if (s_toParse.find_first_of('{') != -1 ||
243  s_toParse.find_first_of('}') != -1 ||
244  s_toParse.find_first_of('[') != -1 ||
245  s_toParse.find_first_of(']') != -1)
246  {
247  TTLogError("TTAddressBase::parse : special regex characters have been detected in %s address\n", s_toParse.data());
248  }
249 
250  // parse directory
251  if (!ttRegexForDirectory->parse(s_toParse.begin(), s_toParse.end()))
252  {
253  s_directory = TTString(ttRegexForDirectory->begin(), ttRegexForDirectory->end());
254  s_toParse.erase(ttRegexForDirectory->begin(), ttRegexForDirectory->end()+1); // +1 to remove ":"
255 
256  // directory:/ case
257  if (s_toParse[0] == C_SEPARATOR && s_toParse[1] == '\0')
258  {
259  this->directory = TTSymbol(s_directory);
260  this->parent = NO_PARENT.getBasePointer();
261  this->name = S_SEPARATOR;
262  this->instance = NO_INSTANCE;
263  this->attribute = NO_ATTRIBUTE;
264  this->type = kAddressAbsolute;
265  this->parsed = YES;
266  this->normalized = kTTAdrsRoot.getBasePointer();
267  return kTTErrNone;
268  }
269  }
270  this->directory = TTSymbol(s_directory);
271 
272  // parse attribute
273  if (!ttRegexForAttribute->parse(s_toParse.begin(), s_toParse.end()))
274  {
275  s_attribute = TTString(ttRegexForAttribute->end(), s_toParse.end());
276  s_toParse.erase(ttRegexForAttribute->begin(), s_toParse.end()-1); // -1 to not erase the last \0
277  }
278  this->attribute = TTSymbol(s_attribute);
279 
280  // parse parent
281  if (!ttRegexForParent->parse(s_toParse.begin(), s_toParse.end()))
282  {
283  // if the split is due to a slash at the beginning : parent = /
284  if (ttRegexForParent->begin() == ttRegexForParent->end())
285  s_parent += C_SEPARATOR;
286 
287  // if directory part exists append it
288  else if (this->directory != kTTSymEmpty)
289  {
290  s_parent = s_directory;
291  s_parent += ":";
292  s_parent += TTString(ttRegexForParent->begin(), ttRegexForParent->end());
293  }
294 
295  else
296  s_parent += TTString(ttRegexForParent->begin(), ttRegexForParent->end());
297 
298  s_toParse.erase(ttRegexForParent->begin(), ttRegexForParent->end()+1); // +1 to remove "/" after parent
299  }
300  this->parent = (TTAddressBase*)gTTAddressTable.lookup(s_parent);
301 
302  // parse instance
303  if (!ttRegexForInstance->parse(s_toParse.begin(), s_toParse.end()))
304  {
305  s_instance = TTString(ttRegexForInstance->end(), s_toParse.end()-1); // -1 to remove a '\0' at the end
306  s_toParse.erase(ttRegexForInstance->begin(), s_toParse.end()-1); // -1 to not erase the last \0
307  }
308  this->instance = TTSymbol(s_instance);
309 
310  // consider the rest is the name
311  this->name = TTSymbol(s_toParse);
312 
313  // the type of the address
314  if (*this->parent != *NO_PARENT.getBasePointer())
315  this->type = this->parent->getType();
316  else
317  this->type = (TTAddressType)(this->directory != NO_DIRECTORY || this->name == S_SEPARATOR);
318 
319  // edit the normalized version of the address
320  this->normalized = edit(NO_DIRECTORY, this->parent, this->name, this->instance, NO_ATTRIBUTE);
321 
322  this->parsed = YES;
323  return kTTErrNone;
324 }
325 
326 
328 {
329  TTErr err1 = kTTErrNone;
330  TTErr err2 = kTTErrNone;
331  TTAddressBase* adrs1;
332  TTAddressBase* adrs2;
333  TTAddressBase* top1;
334  TTAddressBase* rest1;
335  TTAddressBase* top2;
336  TTAddressBase* rest2;
337  bool cParent, cName, cInstance;
338 
339  adrs1 = this->normalize();
340  adrs2 = toCompare->normalize();
341 
342  if (adrs1 == adrs2) {
343 
344  depthDifference = 0;
345 
346  return kAddressEqual;
347  }
348  else if (adrs1 == kTTAdrsRoot) {
349 
350  depthDifference = -(TTInt8(adrs2->countSeparator())); // the depth difference is < 0
351  if (adrs2->getType() == kAddressRelative)
352  depthDifference--;
353 
354  return kAddressUpper;
355  }
356  else if (adrs2 == kTTAdrsRoot) {
357 
358  depthDifference = adrs1->countSeparator(); // the depth diffrence is > 0
359  if (adrs1->getType() == kAddressRelative)
360  depthDifference++;
361 
362  return kAddressLower;
363  }
364  else {
365 
366  err1 = adrs1->splitAt(0, &top1, &rest1);
367  err2 = adrs2->splitAt(0, &top2, &rest2);
368 
369  // compare each level until there is a difference
370  while ((top1 == top2) && (err1 == 0) && (err2 == 0))
371  {
372  err1 = rest1->splitAt(0, &top1, &rest1);
373  err2 = rest2->splitAt(0, &top2, &rest2);
374  }
375 
376  // what are the difference at this level ?
377 
378  // compare parents
379  cParent = top1->getParent() == top2->getParent();
380 
381  // lonely wilcard case : * equals *.*
382  if ((top1->getName() == S_WILDCARD && top1->getInstance() == kTTSymEmpty) || (top2->getName() == S_WILDCARD && top2->getInstance() == kTTSymEmpty)) {
383 
384  cName = YES;
385  cInstance = YES;
386  }
387  else {
388 
389  // compare names
390  cName = (top1->getName() == top2->getName()) || (top1->getName() == S_WILDCARD) || (top2->getName() == S_WILDCARD);
391 
392  // compare instances
393  cInstance = (top1->getInstance() == top2->getInstance()) || (top1->getInstance() == S_WILDCARD) || (top2->getInstance() == S_WILDCARD);
394  }
395 
396  // don't compare attributes
397 
398  // if levels are equal
399  // compare the rest of the address
400  if (cParent && cName && cInstance ){
401 
402  // look at returned error to know if there is a rest
403  if (err1 && !err2) { // address1 is shorter than address2
404  depthDifference = -(TTInt8(rest2->countSeparator())+1); // the depth difference is < 0
405  return kAddressUpper;
406  }
407  else if (!err1 && err2) { // address2 is shorter than address1
408  depthDifference = rest1->countSeparator()+1; // the depth diffrence is > 0
409  return kAddressLower;
410  }
411  else { // address1 ? address2
412  depthDifference = 0;
413  return rest1->compare(rest2, depthDifference);
414  }
415  }
416  }
417 
418  return kAddressDifferent;
419 }
420 
421 TTErr TTAddressBase::splitAt(TTUInt32 whereToSplit, TTAddressBase* *returnedPart1, TTAddressBase* *returnedPart2)
422 {
423  TTErr err = kTTErrNone;
424  TTUInt32 nb, pos, i;
425  TTString part1, part2;
426 
427  i = 0;
428  part1 = "";
429  part2 = this->getCString();
430 
431  while(i <= whereToSplit)
432  {
433  nb = std::count(part2.begin(), part2.end(), C_SEPARATOR);
434 
435  if(nb)
436  {
437  pos = part2.find_first_of(C_SEPARATOR);
438  part1 += part2.substr(0, pos+1);
439  part2 = part2.substr(pos+1, part2.size() - (pos+1));
440  }
441  else
442  {
443  part1 += part2;
444  part2 = "";
445  err = kTTErrGeneric;
446  break;
447  }
448 
449  i++;
450  }
451 
452  // if exists, remove SEPARATOR at the end of the part1
453  if (part1.size()) {
454  if (part1.at(part1.size()-1) == C_SEPARATOR) {
455 
456  // except in case part1 is a directory:/ part
457  size_t sc = part1.find_first_of(':');
458  if (sc > 0 && sc != part1.size()-2)
459  part1 = part1.substr(0, part1.size()-1);
460  }
461  }
462 
463  *returnedPart1 = (TTAddressBase*)gTTAddressTable.lookup(part1);
464  *returnedPart2 = (TTAddressBase*)gTTAddressTable.lookup(part2);
465 
466  return err;
467 }
468 
470 {
471  std::string toCount = this->getCString();
472 
473  return count(toCount.begin(), toCount.end(), C_SEPARATOR);
474 }
475 
476 TTErr TTAddressBase::listNameInstance(TTList& nameInstanceList)
477 {
478  if (!parsed) parse();
479 
480  if (*this != kTTAdrsEmpty && *this != kTTAdrsRoot) {
481 
482  this->parent->listNameInstance(nameInstanceList);
483 
484  // if there is a directory part : append directory and ""
485  if (directory != NO_DIRECTORY) {
486 
487  if (this->parent == kTTAdrsRoot) {
488  nameInstanceList.append(directory);
489  nameInstanceList.append(kTTSymEmpty);
490  }
491  // directory:/ case
492  else if (this->parent == NO_PARENT && this->name == S_SEPARATOR) {
493  nameInstanceList.append(directory);
494  nameInstanceList.append(kTTSymEmpty);
495  return kTTErrNone;
496  }
497  }
498 
499  nameInstanceList.append(name);
500  nameInstanceList.append(instance);
501  }
502 
503  return kTTErrNone;
504 }
505 
506 #endif
TTAddressBase * appendInstance(const TTSymbol &anInstance)
Return a new TTAddress with a instance part.
TTSymbol & getDirectory()
Get the directory part.
this flag means that address1 an address2 refer to nodes which are in a different branch in the tree ...
Definition: TTAddressBase.h:47
TTErr listNameInstance(TTList &nameInstanceList)
A parsing tool : return a list containing all name.instance part (without any S_SEPARATOR) ...
TTAddressComparisonFlag compare(TTAddressBase *toCompare, TTInt8 &depthDifference)
A comparison tool.
TTSymbolBase * lookup(const char *aString)
Look in the symbol table for this string.
TTAddressType getType()
Get the type.
STL namespace.
An address could be.
Definition: TTAddressBase.h:84
TTSymbol getNameInstance()
Get the name.instance part.
this flag means that an address have no leading slash
Definition: TTAddressBase.h:64
TTSymbol & getAttribute()
Get the attribute part.
TTAddressType
Type flags to state about absolute or relative address.
Definition: TTAddressBase.h:63
The TTSymbolBase class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbolBase.h:28
TTAddressBase * appendAddress(TTAddressBase *toAppend)
Return a new TTAddress with the appended part.
TTAddressBase(const TTString &newAddressString, TTPtrSizedInt newAddressTableId, TTInt32 newId)
Constructor.
const char * getCString() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbolBase.h:55
this flag means that address1 an address2 refer to the same node in the tree structure ...
Definition: TTAddressBase.h:48
The TTSymbol class is used to represent a string and efficiently pass and compare that string...
Definition: TTSymbol.h:26
void TTFOUNDATION_EXPORT TTLogError(TTImmutableCString message,...)
Platform and host independent method for posting errors.
Definition: TTBase.cpp:572
TTUInt32 countSeparator()
A parsing tool : count how many C_SEPARATOR there is in the address.
void init(const TTString &newString, TTPtrSizedInt newSymbolTableId, TTInt32 newSymbolId)
used by the constructors to create the new symbol
TTAddressBase * removeAttribute()
Return a new TTAddress without attribute part.
TTErr splitAt(TTUInt32 whereToSplit, TTAddressBase **returnedPart1, TTAddressBase **returnedPart2)
A parsing tool : split address in two part from a given '/' position.
this flag means that an address have a leading slash
Definition: TTAddressBase.h:65
this flag means that address1 refers to a node at a lower level than address2 in the tree structure ...
Definition: TTAddressBase.h:46
TTAddressBase * normalize()
Normalize an address for lookup and other directory operations This would return an address without d...
TTString substr(size_t pos=0, size_t n=1) const
Returns a string object with its contents initialized to a substring of the current object...
Definition: TTString.h:342
const char * c_str() const
Return a pointer to the internal string as a C-string.
Definition: TTSymbol.h:77
std::int32_t TTInt32
32 bit signed integer
Definition: TTBase.h:177
TTSymbol & getInstance()
Get the instance part.
TTSymbol & getName()
Get the name part.
TTAddressComparisonFlag
Comparison flags between address returned by address1->compare(address2).
Definition: TTAddressBase.h:45
this flag means that address1 refers to a node at a upper level than address2 in the tree structure ...
Definition: TTAddressBase.h:49
long TTPtrSizedInt
An integer that is the same size as a pointer.
Definition: TTBase.h:240
Something went wrong, but what exactly is not known. Typically used for context-specific problems...
Definition: TTBase.h:344
TTErr
Jamoma Error Codes Enumeration of error codes that might be returned by any of the TTBlue functions a...
Definition: TTBase.h:342
TTAddressBase * appendAttribute(TTSymbol &anAttribute)
Return a new TTAddress with attribute part.
signed char TTInt8
8 bit signed integer (char)
Definition: TTBase.h:173
std::uint32_t TTUInt32
32 bit unsigned integer
Definition: TTBase.h:178
size_t size() const
Find out the length of a string.
Definition: TTString.h:144
TTAddressBase * getParent()
Get a pointer to the parent address.
size_t find_first_of(const char aChar, size_t from=0)
Return the index of the first instance of a specified char in the string.
Definition: TTString.h:296
No Error.
Definition: TTBase.h:343
virtual ~TTAddressBase()
Destructor.
The TTString class is used to represent a string.
Definition: TTString.h:34
TTAddressBase * edit(const TTSymbol &newDirectory, const TTAddressBase *newParent, const TTSymbol &newName, const TTSymbol &newInstance, const TTSymbol &newAttribute)
Edit address from directory, parent, name, instance and attribute part.