String::CPtr percentDecode(String::CPtr str, String::Encoding enc) { if (!str || str->isEmpty()) return String::create(); Size len = str->length() + 1; char* decoded = new char[len]; Size size = percentDecode(decoded, len, str->toStdString().c_str()); String::CPtr res; switch (enc) { case String::UTF8: res = String::create(decoded, enc, size); break; case String::UTF16: case String::UTF16BE: case String::UTF16LE: res = String::create(decoded, enc, size >> 1); break; case String::UTF32: case String::UTF32BE: case String::UTF32LE: res = String::create(decoded, enc, size >> 2); break; default: assert(false); res = String::null(); } delete[] decoded; return res; }
static inline Size indexOfSep(String::CPtr str, Size from) { assert(str); Size len = str->length(); for (Size i = from; i < len; i++) { if (isSep(str->charAt(i))) return i; } return NO_POS; }
String::CPtr dirname(String::CPtr path) { LIBJ_STATIC_SYMBOL_DEF(symCurrent, "."); if (!path) return symCurrent; path = trimSeps(path); String::CPtr base = basename(path); Size baseLen = base->length(); Size pathLen = path->length(); if (baseLen == pathLen) { return symCurrent; } else { Size sepPos = pathLen - baseLen - 1; assert(isSep(path->charAt(sepPos))); if (sepPos) { return path->substring(0, sepPos); } else { return path->substring(0, 1); } } }
String::CPtr percentEncode(String::CPtr str, String::Encoding enc) { static const Boolean isBigEndian = endian() == BIG; if (!str || str->length() == 0) return String::create(); Buffer::Ptr buf; switch (enc) { case String::UTF8: buf = Buffer::create(str, Buffer::UTF8); break; case String::UTF16: if (isBigEndian) { buf = Buffer::create(str, Buffer::UTF16BE); } else { buf = Buffer::create(str, Buffer::UTF16LE); } break; case String::UTF16BE: buf = Buffer::create(str, Buffer::UTF16BE); break; case String::UTF16LE: buf = Buffer::create(str, Buffer::UTF16LE); break; case String::UTF32: if (isBigEndian) { buf = Buffer::create(str, Buffer::UTF32BE); } else { buf = Buffer::create(str, Buffer::UTF32LE); } break; case String::UTF32BE: buf = Buffer::create(str, Buffer::UTF32BE); break; case String::UTF32LE: buf = Buffer::create(str, Buffer::UTF32LE); break; default: assert(false); buf = Buffer::null(); } Size sourceLen = buf->length(); const char* source = static_cast<const char*>(buf->data()); Size encodedLen = sourceLen * 3 + 1; char* encoded = new char[encodedLen]; percentEncode(encoded, encodedLen, source, sourceLen); String::CPtr res = String::create(encoded); delete[] encoded; return res; }
static inline String::CPtr trimSeps(String::CPtr str) { assert(str); Size len = str->length(); if (!len) return str; Size i = len - 1; while (1) { if (!isSep(str->charAt(i))) { return str->substring(0, i + 1); } if (i) { i--; } else { break; } } return str->substring(0, 1); }
static inline Size lastIndexOfSep(String::CPtr str, Size from = NO_POS) { assert(str); Size len = str->length(); if (!len) return NO_POS; if (from >= len) from = len - 1; Size i = from; while (1) { if (isSep(str->charAt(i))) return i; if (i) { i--; } else { break; } } return NO_POS; }
String::CPtr normalize(String::CPtr path) { LIBJ_STATIC_SYMBOL_DEF(symCurrent, "."); LIBJ_STATIC_SYMBOL_DEF(symParent, ".."); LIBJ_STATIC_SYMBOL_DEF(symNull, "null"); if (!path) return symNull; Boolean absolute = false; Boolean endsWithSep = false; typedef TypedJsArray<String::CPtr> StringArray; StringArray::Ptr dirs = StringArray::create(); Size len = path->length(); for (Size i = 0; i < len;) { Size idx = indexOfSep(path, i); if (idx == 0) { absolute = true; } else if (idx != i) { String::CPtr dir; if (idx == NO_POS) { dir = path->substring(i); } else { dir = path->substring(i, idx); } if (dir->equals(symParent)) { Size numDirs = dirs->size(); if (numDirs > 0 && !dirs->getTyped(numDirs - 1)->equals(symParent)) { dirs->removeTyped(numDirs - 1); } else { dirs->addTyped(dir); } } else if (!dir->equals(symCurrent)) { dirs->addTyped(dir); } } if (idx == NO_POS) { endsWithSep = false; i = len; } else { endsWithSep = true; i = idx + 1; } } StringBuilder::Ptr normal = StringBuilder::create(); if (absolute) normal->appendChar(SEP); Size numDirs = dirs->size(); for (Size i = 0; i < numDirs; i++) { if (i) normal->appendChar(SEP); normal->appendStr(dirs->getTyped(i)); } if (numDirs > 0 && endsWithSep) normal->appendChar(SEP); if (normal->length() == 0) { return symCurrent; } else { return normal->toString(); } }