00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 #ifndef OSCPKT_HH
00057 #define OSCPKT_HH
00058
00059 #ifndef _MSC_VER
00060 #include <stdint.h>
00061 #else
00062 namespace oscpkt {
00063 typedef __int32 int32_t;
00064 typedef unsigned __int32 uint32_t;
00065 typedef __int64 int64_t;
00066 typedef unsigned __int64 uint64_t;
00067 }
00068 #endif
00069 #include <cstring>
00070 #include <cassert>
00071 #include <string>
00072 #include <vector>
00073 #include <list>
00074
00075 #if defined(OSCPKT_OSTREAM_OUTPUT) || defined(OSCPKT_TEST)
00076 #include <iostream>
00077 #endif
00078
00079 namespace oscpkt {
00080
00081
00082
00083
00084 class TimeTag {
00085 uint64_t v;
00086 public:
00087 TimeTag() : v(1) {}
00088 explicit TimeTag(uint64_t w): v(w) {}
00089 operator uint64_t() const { return v; }
00090 static TimeTag immediate() { return TimeTag(1); }
00091 };
00092
00093
00094 enum {
00095 TYPE_TAG_TRUE = 'T',
00096 TYPE_TAG_FALSE = 'F',
00097 TYPE_TAG_INT32 = 'i',
00098 TYPE_TAG_INT64 = 'h',
00099 TYPE_TAG_FLOAT = 'f',
00100 TYPE_TAG_DOUBLE = 'd',
00101 TYPE_TAG_STRING = 's',
00102 TYPE_TAG_BLOB = 'b'
00103 };
00104
00105
00106
00107
00108 template <typename Type> Type ceil4(Type p) { return (Type)((size_t(p) + 3)&(~size_t(3))); }
00109
00110
00111 inline bool isZeroPaddingCorrect(const char *p) {
00112 const char *q = ceil4(p);
00113 for (;p < q; ++p)
00114 if (*p != 0) { return false; }
00115 return true;
00116 }
00117
00118
00119 template <typename POD> union PodBytes {
00120 char bytes[sizeof(POD)];
00121 POD value;
00122 };
00123
00124 inline bool isBigEndian() {
00125 PodBytes<int32_t> p; p.value = 0x12345678;
00126 return p.bytes[0] == 0x12;
00127 }
00128
00129
00130 template <typename POD> POD bytes2pod(const char *bytes) {
00131 PodBytes<POD> p;
00132 for (size_t i=0; i < sizeof(POD); ++i) {
00133 if (isBigEndian())
00134 p.bytes[i] = bytes[i];
00135 else
00136 p.bytes[i] = bytes[sizeof(POD) - i - 1];
00137 }
00138 return p.value;
00139 }
00140
00141
00142 template <typename POD> void pod2bytes(const POD value, char *bytes) {
00143 PodBytes<POD> p; p.value = value;
00144 for (size_t i=0; i < sizeof(POD); ++i) {
00145 if (isBigEndian())
00146 bytes[i] = p.bytes[i];
00147 else
00148 bytes[i] = p.bytes[sizeof(POD) - i - 1];
00149 }
00150 }
00151
00152
00153 struct Storage {
00154 std::vector<char> data;
00155 Storage() { data.reserve(200); }
00156 char *getBytes(size_t sz) {
00157 assert((data.size() & 3) == 0);
00158 if (data.size() + sz > data.capacity()) { data.reserve((data.size() + sz)*2); }
00159 size_t sz4 = ceil4(sz);
00160 size_t pos = data.size();
00161 data.resize(pos + sz4);
00162 return &(data[pos]);
00163 }
00164 char *begin() { return data.size() ? &data.front() : 0; }
00165 char *end() { return begin() + size(); }
00166 const char *begin() const { return data.size() ? &data.front() : 0; }
00167 const char *end() const { return begin() + size(); }
00168 size_t size() const { return data.size(); }
00169 void assign(const char *beg, const char *end) { data.assign(beg, end); }
00170 void clear() { data.resize(0); }
00171 };
00172
00173
00174
00175 bool fullPatternMatch(const std::string &pattern, const std::string &path);
00176
00177 bool partialPatternMatch(const std::string &pattern, const std::string &path);
00178
00179 #if defined(OSCPKT_DEBUG)
00180 #define OSCPKT_SET_ERR(errcode) do { if (!err) { err = errcode; std::cerr << "set " #errcode << " at line " << __LINE__ << "\n"; } } while (0)
00181 #else
00182 #define OSCPKT_SET_ERR(errcode) do { if (!err) err = errcode; } while (0)
00183 #endif
00184
00185 typedef enum { OK_NO_ERROR=0,
00186
00187 MALFORMED_ADDRESS_PATTERN, MALFORMED_TYPE_TAGS, MALFORMED_ARGUMENTS, UNHANDLED_TYPE_TAGS,
00188
00189 TYPE_MISMATCH, NOT_ENOUGH_ARG, PATTERN_MISMATCH,
00190
00191 INVALID_BUNDLE, INVALID_PACKET_SIZE, BUNDLE_REQUIRED_FOR_MULTI_MESSAGES } ErrorCode;
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 class Message {
00219 TimeTag time_tag;
00220 std::string address;
00221 std::string type_tags;
00222 std::vector<std::pair<size_t, size_t> > arguments;
00223 Storage storage;
00224 ErrorCode err;
00225 public:
00226
00227
00228 class ArgReader {
00229 const Message *msg;
00230 ErrorCode err;
00231 size_t arg_idx;
00232 public:
00233 ArgReader(const Message &m, ErrorCode e = OK_NO_ERROR) : msg(&m), err(msg->getErr()), arg_idx(0) {
00234 if (e != OK_NO_ERROR && err == OK_NO_ERROR) err=e;
00235 }
00236 ArgReader(const ArgReader &other) : msg(other.msg), err(other.err), arg_idx(other.arg_idx) {}
00237 bool isBool() { return currentTypeTag() == TYPE_TAG_TRUE || currentTypeTag() == TYPE_TAG_FALSE; }
00238 bool isInt32() { return currentTypeTag() == TYPE_TAG_INT32; }
00239 bool isInt64() { return currentTypeTag() == TYPE_TAG_INT64; }
00240 bool isFloat() { return currentTypeTag() == TYPE_TAG_FLOAT; }
00241 bool isDouble() { return currentTypeTag() == TYPE_TAG_DOUBLE; }
00242 bool isStr() { return currentTypeTag() == TYPE_TAG_STRING; }
00243 bool isBlob() { return currentTypeTag() == TYPE_TAG_BLOB; }
00244
00245 size_t nbArgRemaining() const { return msg->arguments.size() - arg_idx; }
00246 bool isOk() const { return err == OK_NO_ERROR; }
00247 operator bool() const { return isOk(); }
00248
00249
00250 bool isOkNoMoreArgs() const { return err == OK_NO_ERROR && nbArgRemaining() == 0; }
00251 ErrorCode getErr() const { return err; }
00252
00253
00254 ArgReader &popInt32(int32_t &i) { return popPod<int32_t>(TYPE_TAG_INT32, i); }
00255
00256 ArgReader &popInt64(int64_t &i) { return popPod<int64_t>(TYPE_TAG_INT64, i); }
00257
00258 ArgReader &popFloat(float &f) { return popPod<float>(TYPE_TAG_FLOAT, f); }
00259
00260 ArgReader &popDouble(double &d) { return popPod<double>(TYPE_TAG_DOUBLE, d); }
00261
00262 ArgReader &popStr(std::string &s) {
00263 if (precheck(TYPE_TAG_STRING)) {
00264 s = argBeg(arg_idx++);
00265 }
00266 return *this;
00267 }
00268
00269 ArgReader &popBlob(std::vector<char> &b) {
00270 if (precheck(TYPE_TAG_BLOB)) {
00271 b.assign(argBeg(arg_idx)+4, argEnd(arg_idx));
00272 ++arg_idx;
00273 }
00274 return *this;
00275 }
00276
00277 ArgReader &popBool(bool &b) {
00278 b = false;
00279 if (arg_idx >= msg->arguments.size()) OSCPKT_SET_ERR(NOT_ENOUGH_ARG);
00280 else if (currentTypeTag() == TYPE_TAG_TRUE) b = true;
00281 else if (currentTypeTag() == TYPE_TAG_FALSE) b = false;
00282 else OSCPKT_SET_ERR(TYPE_MISMATCH);
00283 ++arg_idx;
00284 return *this;
00285 }
00286
00287 ArgReader &pop() {
00288 if (arg_idx >= msg->arguments.size()) OSCPKT_SET_ERR(NOT_ENOUGH_ARG);
00289 else ++arg_idx;
00290 return *this;
00291 }
00292 private:
00293 const char *argBeg(size_t idx) {
00294 if (err || idx >= msg->arguments.size()) return 0;
00295 else return msg->storage.begin() + msg->arguments[idx].first;
00296 }
00297 const char *argEnd(size_t idx) {
00298 if (err || idx >= msg->arguments.size()) return 0;
00299 else return msg->storage.begin() + msg->arguments[idx].first + msg->arguments[idx].second;
00300 }
00301 int currentTypeTag() {
00302 if (!err && arg_idx < msg->type_tags.size()) return msg->type_tags[arg_idx];
00303 else OSCPKT_SET_ERR(NOT_ENOUGH_ARG);
00304 return -1;
00305 }
00306 template <typename POD> ArgReader &popPod(int tag, POD &v) {
00307 if (precheck(tag)) {
00308 v = bytes2pod<POD>(argBeg(arg_idx));
00309 ++arg_idx;
00310 } else v = POD(0);
00311 return *this;
00312 }
00313
00314 bool precheck(int tag) {
00315 if (arg_idx >= msg->arguments.size()) OSCPKT_SET_ERR(NOT_ENOUGH_ARG);
00316 else if (!err && currentTypeTag() != tag) OSCPKT_SET_ERR(TYPE_MISMATCH);
00317 return err == OK_NO_ERROR;
00318 }
00319 };
00320
00321 Message() { clear(); }
00322 Message(const std::string &s, TimeTag tt = TimeTag::immediate()) : time_tag(tt), address(s), err(OK_NO_ERROR) {}
00323 Message(const void *ptr, size_t sz, TimeTag tt = TimeTag::immediate()) { buildFromRawData(ptr, sz); time_tag = tt; }
00324
00325 bool isOk() const { return err == OK_NO_ERROR; }
00326 ErrorCode getErr() const { return err; }
00327
00328
00329 const std::string &typeTags() const { return type_tags; }
00330
00331
00332
00333 const std::string &addressPattern() const { return address; }
00334 TimeTag timeTag() const { return time_tag; }
00335
00336 Message &init(const std::string &addr, TimeTag tt = TimeTag::immediate()) {
00337 clear();
00338 address = addr; time_tag = tt;
00339 if (address.empty() || address[0] != '/') OSCPKT_SET_ERR(MALFORMED_ADDRESS_PATTERN);
00340 return *this;
00341 }
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353 ArgReader match(const std::string &test) const {
00354 return ArgReader(*this, fullPatternMatch(address.c_str(), test.c_str()) ? OK_NO_ERROR : PATTERN_MISMATCH);
00355 }
00356
00357
00358 ArgReader partialMatch(const std::string &test) const {
00359 return ArgReader(*this, partialPatternMatch(address.c_str(), test.c_str()) ? OK_NO_ERROR : PATTERN_MISMATCH);
00360 }
00361 ArgReader arg() const { return ArgReader(*this, OK_NO_ERROR); }
00362
00363
00364 void buildFromRawData(const void *ptr, size_t sz) {
00365 clear();
00366 storage.assign((const char*)ptr, (const char*)ptr + sz);
00367 const char *address_beg = storage.begin();
00368 const char *address_end = (const char*)memchr(address_beg, 0, storage.end()-address_beg);
00369 if (!address_end || !isZeroPaddingCorrect(address_end+1) || address_beg[0] != '/') {
00370 OSCPKT_SET_ERR(MALFORMED_ADDRESS_PATTERN); return;
00371 } else address.assign(address_beg, address_end);
00372
00373 const char *type_tags_beg = ceil4(address_end+1);
00374 const char *type_tags_end = (const char*)memchr(type_tags_beg, 0, storage.end()-type_tags_beg);
00375 if (!type_tags_end || !isZeroPaddingCorrect(type_tags_end+1) || type_tags_beg[0] != ',') {
00376 OSCPKT_SET_ERR(MALFORMED_TYPE_TAGS); return;
00377 } else type_tags.assign(type_tags_beg+1, type_tags_end);
00378
00379 const char *arg = ceil4(type_tags_end+1); assert(arg <= storage.end());
00380 size_t iarg = 0;
00381 while (isOk() && iarg < type_tags.size()) {
00382 assert(arg <= storage.end());
00383 size_t len = getArgSize(type_tags[iarg], arg);
00384 if (isOk()) arguments.push_back(std::make_pair(arg - storage.begin(), len));
00385 arg += ceil4(len); ++iarg;
00386 }
00387 if (iarg < type_tags.size() || arg != storage.end()) {
00388 OSCPKT_SET_ERR(MALFORMED_ARGUMENTS);
00389 }
00390 }
00391
00392
00393 Message &pushBool(bool b) {
00394 type_tags += (b ? TYPE_TAG_TRUE : TYPE_TAG_FALSE);
00395 arguments.push_back(std::make_pair(storage.size(), storage.size()));
00396 return *this;
00397 }
00398 Message &pushInt32(int32_t i) { return pushPod(TYPE_TAG_INT32, i); }
00399 Message &pushInt64(int64_t h) { return pushPod(TYPE_TAG_INT64, h); }
00400 Message &pushFloat(float f) { return pushPod(TYPE_TAG_FLOAT, f); }
00401 Message &pushDouble(double d) { return pushPod(TYPE_TAG_DOUBLE, d); }
00402 Message &pushStr(const std::string &s) {
00403 assert(s.size() < 2147483647);
00404 type_tags += TYPE_TAG_STRING;
00405 arguments.push_back(std::make_pair(storage.size(), s.size() + 1));
00406 strcpy(storage.getBytes(s.size()+1), s.c_str());
00407 return *this;
00408 }
00409 Message &pushBlob(void *ptr, size_t num_bytes) {
00410 assert(num_bytes < 2147483647);
00411 type_tags += TYPE_TAG_BLOB;
00412 arguments.push_back(std::make_pair(storage.size(), num_bytes+4));
00413 pod2bytes<int32_t>((int32_t)num_bytes, storage.getBytes(4));
00414 if (num_bytes)
00415 memcpy(storage.getBytes(num_bytes), ptr, num_bytes);
00416 return *this;
00417 }
00418
00419
00420 void clear() {
00421 address.clear(); type_tags.clear(); storage.clear(); arguments.clear();
00422 err = OK_NO_ERROR; time_tag = TimeTag::immediate();
00423 }
00424
00425
00426 void packMessage(Storage &s, bool write_size) const {
00427 if (!isOk()) return;
00428 size_t l_addr = address.size()+1, l_type = type_tags.size()+2;
00429 if (write_size)
00430 pod2bytes<uint32_t>(uint32_t(ceil4(l_addr) + ceil4(l_type) + ceil4(storage.size())), s.getBytes(4));
00431 strcpy(s.getBytes(l_addr), address.c_str());
00432 strcpy(s.getBytes(l_type), ("," + type_tags).c_str());
00433 if (storage.size())
00434 memcpy(s.getBytes(storage.size()), const_cast<Storage&>(storage).begin(), storage.size());
00435 }
00436
00437 private:
00438
00439
00440 size_t getArgSize(int type, const char *p) {
00441 if (err) return 0;
00442 size_t sz = 0;
00443 assert(p >= storage.begin() && p <= storage.end());
00444 switch (type) {
00445 case TYPE_TAG_TRUE:
00446 case TYPE_TAG_FALSE: sz = 0; break;
00447 case TYPE_TAG_INT32:
00448 case TYPE_TAG_FLOAT: sz = 4; break;
00449 case TYPE_TAG_INT64:
00450 case TYPE_TAG_DOUBLE: sz = 8; break;
00451 case TYPE_TAG_STRING: {
00452 const char *q = (const char*)memchr(p, 0, storage.end()-p);
00453 if (!q) OSCPKT_SET_ERR(MALFORMED_ARGUMENTS);
00454 else sz = (q-p)+1;
00455 } break;
00456 case TYPE_TAG_BLOB: {
00457 if (p == storage.end()) { OSCPKT_SET_ERR(MALFORMED_ARGUMENTS); return 0; }
00458 sz = 4+bytes2pod<uint32_t>(p);
00459 } break;
00460 default: {
00461 OSCPKT_SET_ERR(UNHANDLED_TYPE_TAGS); return 0;
00462 } break;
00463 }
00464 if (p+sz > storage.end() ||
00465 p+sz < p ) {
00466 OSCPKT_SET_ERR(MALFORMED_ARGUMENTS); return 0;
00467 }
00468 if (!isZeroPaddingCorrect(p+sz)) { OSCPKT_SET_ERR(MALFORMED_ARGUMENTS); return 0; }
00469 return sz;
00470 }
00471
00472 template <typename POD> Message &pushPod(int tag, POD v) {
00473 type_tags += (char)tag;
00474 arguments.push_back(std::make_pair(storage.size(), sizeof(POD)));
00475 pod2bytes(v, storage.getBytes(sizeof(POD)));
00476 return *this;
00477 }
00478
00479 #ifdef OSCPKT_OSTREAM_OUTPUT
00480 friend std::ostream &operator<<(std::ostream &os, const Message &msg) {
00481 os << "osc_address: '" << msg.address << "', types: '" << msg.type_tags << "', timetag=" << msg.time_tag << ", args=[";
00482 Message::ArgReader arg(msg);
00483 while (arg.nbArgRemaining() && arg.isOk()) {
00484 if (arg.isBool()) { bool b; arg.popBool(b); os << (b?"True":"False"); }
00485 else if (arg.isInt32()) { int32_t i; arg.popInt32(i); os << i; }
00486 else if (arg.isInt64()) { int64_t h; arg.popInt64(h); os << h << "ll"; }
00487 else if (arg.isFloat()) { float f; arg.popFloat(f); os << f << "f"; }
00488 else if (arg.isDouble()) { double d; arg.popDouble(d); os << d; }
00489 else if (arg.isStr()) { std::string s; arg.popStr(s); os << "'" << s << "'"; }
00490 else if (arg.isBlob()) { std::vector<char> b; arg.popBlob(b); os << "Blob " << b.size() << " bytes"; }
00491 else {
00492 assert(0);
00493 }
00494 if (arg.nbArgRemaining()) os << ", ";
00495 }
00496 if (!arg.isOk()) { os << " ERROR#" << arg.getErr(); }
00497 os << "]";
00498 return os;
00499 }
00500 #endif
00501 };
00502
00503
00504
00505
00506 class PacketReader {
00507 public:
00508 PacketReader() { err = OK_NO_ERROR; }
00509
00510 PacketReader(const void *ptr, size_t sz) { init(ptr, sz); }
00511
00512 void init(const void *ptr, size_t sz) {
00513 err = OK_NO_ERROR; messages.clear();
00514 if ((sz%4) == 0) {
00515 parse((const char*)ptr, (const char *)ptr+sz, TimeTag::immediate());
00516 } else OSCPKT_SET_ERR(INVALID_PACKET_SIZE);
00517 it_messages = messages.begin();
00518 }
00519
00520
00521 Message *popMessage() {
00522 if (!err && !messages.empty() && it_messages != messages.end()) return &*it_messages++;
00523 else return 0;
00524 }
00525 bool isOk() const { return err == OK_NO_ERROR; }
00526 ErrorCode getErr() const { return err; }
00527
00528 private:
00529 std::list<Message> messages;
00530 std::list<Message>::iterator it_messages;
00531 ErrorCode err;
00532
00533 void parse(const char *beg, const char *end, TimeTag time_tag) {
00534 assert(beg <= end && !err); assert(((end-beg)%4)==0);
00535
00536 if (beg == end) return;
00537 if (*beg == '#') {
00538
00539 if (end - beg >= 20
00540 && memcmp(beg, "#bundle\0", 8) == 0) {
00541 TimeTag time_tag2(bytes2pod<uint64_t>(beg+8));
00542 const char *pos = beg + 16;
00543 do {
00544 uint32_t sz = bytes2pod<uint32_t>(pos); pos += 4;
00545 if ((sz&3) != 0 || pos + sz > end || pos+sz < pos) {
00546 OSCPKT_SET_ERR(INVALID_BUNDLE);
00547 } else {
00548 parse(pos, pos+sz, time_tag2);
00549 pos += sz;
00550 }
00551 } while (!err && pos != end);
00552 } else {
00553 OSCPKT_SET_ERR(INVALID_BUNDLE);
00554 }
00555 } else {
00556 messages.push_back(Message(beg, end-beg, time_tag));
00557 if (!messages.back().isOk()) OSCPKT_SET_ERR(messages.back().getErr());
00558 }
00559 }
00560 };
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 class PacketWriter {
00578 public:
00579 PacketWriter() { init(); }
00580 PacketWriter &init() { err = OK_NO_ERROR; storage.clear(); bundles.clear(); return *this; }
00581
00582
00583
00584 PacketWriter &startBundle(TimeTag ts = TimeTag::immediate()) {
00585 char *p;
00586 if (bundles.size()) p = storage.getBytes(4);
00587 p = storage.getBytes(8); strcpy(p, "#bundle"); bundles.push_back(p - storage.begin());
00588 p = storage.getBytes(8); pod2bytes<uint64_t>(ts, p);
00589 return *this;
00590 }
00591
00592 PacketWriter &endBundle() {
00593 if (bundles.size()) {
00594 if (storage.size() - bundles.back() == 16) {
00595 pod2bytes<uint32_t>(0, storage.getBytes(4));
00596 }
00597 if (bundles.size()>1) {
00598 pod2bytes<uint32_t>(uint32_t(storage.size() - bundles.back()), storage.begin() + bundles.back()-4);
00599 }
00600 bundles.pop_back();
00601 } else OSCPKT_SET_ERR(INVALID_BUNDLE);
00602 return *this;
00603 }
00604
00605
00606
00607 PacketWriter &addMessage(const Message &msg) {
00608 if (storage.size() != 0 && bundles.empty()) OSCPKT_SET_ERR(BUNDLE_REQUIRED_FOR_MULTI_MESSAGES);
00609 else msg.packMessage(storage, bundles.size()>0);
00610 if (!msg.isOk()) OSCPKT_SET_ERR(msg.getErr());
00611 return *this;
00612 }
00613
00614
00615
00616 bool isOk() { return err == OK_NO_ERROR; }
00617 ErrorCode getErr() { return err; }
00618
00619
00620
00621
00622 uint32_t packetSize() { return err ? 0 : storage.size(); }
00623
00624
00625 char *packetData() { return err ? 0 : storage.begin(); }
00626 private:
00627 std::vector<size_t> bundles;
00628 Storage storage;
00629 ErrorCode err;
00630 };
00631
00632
00633 inline const char *internalPatternMatch(const char *pattern, const char *path) {
00634 while (*pattern) {
00635 const char *p = pattern;
00636 if (*p == '?' && *path) { ++p; ++path; }
00637 else if (*p == '[' && *path) {
00638 ++p;
00639 bool reverse = false;
00640 if (*p == '!') { reverse = true; ++p; }
00641 bool match = reverse;
00642 for (; *p && *p != ']'; ++p) {
00643 char c0 = *p, c1 = c0;
00644 if (p[1] == '-' && p[2]) { p += 2; c1 = *p; }
00645 if (*path >= c0 && *path <= c1) { match = !reverse; }
00646 }
00647 if (!match || *p != ']') return pattern;
00648 ++p; ++path;
00649 } else if (*p == '*') {
00650 while (*p == '*') ++p;
00651 const char *best = 0;
00652 while (true) {
00653 const char *ret = internalPatternMatch(p, path);
00654 if (ret && ret > best) best = ret;
00655 if (*path == 0 || *path == '/') break;
00656 else ++path;
00657 }
00658 return best;
00659 } else if (*p == '/' && *(p+1) == '/') {
00660 while (*(p+1)=='/') ++p;
00661 const char *best = 0;
00662 while (true) {
00663 const char *ret = internalPatternMatch(p, path);
00664 if (ret && ret > best) best = ret;
00665 if (*path == 0) break;
00666 if (*path == 0 || (path = strchr(path+1, '/')) == 0) break;
00667 }
00668 return best;
00669 } else if (*p == '{') {
00670 const char *end = strchr(p, '}'), *q;
00671 if (!end) return 0;
00672 bool match = false;
00673 do {
00674 ++p;
00675 q = strchr(p, ',');
00676 if (q == 0 || q > end) q = end;
00677 if (strncmp(p, path, q-p)==0) {
00678 path += (q-p); p = end+1; match = true;
00679 } else p=q;
00680 } while (q != end && !match);
00681 if (!match) return pattern;
00682 } else if (*p == *path) { ++p; ++path; }
00683 else break;
00684 pattern = p;
00685 }
00686 return (*path == 0 ? pattern : 0);
00687 }
00688
00689 inline bool partialPatternMatch(const std::string &pattern, const std::string &test) {
00690 const char *q = internalPatternMatch(pattern.c_str(), test.c_str());
00691 return q != 0;
00692 }
00693
00694 inline bool fullPatternMatch(const std::string &pattern, const std::string &test) {
00695 const char *q = internalPatternMatch(pattern.c_str(), test.c_str());
00696 return q && *q == 0;
00697 }
00698
00699 }
00700
00701 #endif // OSCPKT_HH