std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& event, std::ostream& os) { static const size_t maxLogLine = 10 * 1024; _dateFormatter(os, event.getDate()); os << ' '; os << event.getSeverity().toChar(); os << ' '; LogComponent component = event.getComponent(); os << component; os << ' '; StringData contextName = event.getContextName(); if (!contextName.empty()) { os << '[' << contextName << "] "; } StringData msg = event.getMessage(); if (msg.size() > maxLogLine) { os << "warning: log line attempted (" << msg.size() / 1024 << "k) over max size (" << maxLogLine / 1024 << "k), printing beginning and end ... "; os << msg.substr(0, maxLogLine / 3); os << " .......... "; os << msg.substr(msg.size() - (maxLogLine / 3)); } else { os << msg; } if (!msg.endsWith(StringData("\n", StringData::LiteralTag()))) os << '\n'; return os; }
Status WhereMatchExpression::init( const StringData& ns, const StringData& theCode, const BSONObj& scope ) { if ( ns.size() == 0 ) return Status( ErrorCodes::BadValue, "ns for $where cannot be empty" ); if ( theCode.size() == 0 ) return Status( ErrorCodes::BadValue, "code for $where cannot be empty" ); _ns = ns.toString(); _code = theCode.toString(); _userScope = scope.getOwned(); NamespaceString nswrapper( _ns ); const string userToken = ClientBasic::getCurrent()->getAuthorizationSession() ->getAuthenticatedUserNamesToken(); _scope = globalScriptEngine->getPooledScope( nswrapper.db().toString(), "where" + userToken ); _func = _scope->createFunction( _code.c_str() ); if ( !_func ) return Status( ErrorCodes::BadValue, "$where compile error" ); return Status::OK(); }
Status Database::validateDBName( const StringData& dbname ) { if ( dbname.size() <= 0 ) return Status( ErrorCodes::BadValue, "db name is empty" ); if ( dbname.size() >= 64 ) return Status( ErrorCodes::BadValue, "db name is too long" ); if ( dbname.find( '.' ) != string::npos ) return Status( ErrorCodes::BadValue, "db name cannot contain a ." ); if ( dbname.find( ' ' ) != string::npos ) return Status( ErrorCodes::BadValue, "db name cannot contain a space" ); #ifdef _WIN32 static const char* windowsReservedNames[] = { "con", "prn", "aux", "nul", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9" }; string lower( dbname.toString() ); std::transform( lower.begin(), lower.end(), lower.begin(), ::tolower ); for ( size_t i = 0; i < (sizeof(windowsReservedNames) / sizeof(char*)); ++i ) { if ( lower == windowsReservedNames[i] ) { stringstream errorString; errorString << "db name \"" << dbname.toString() << "\" is a reserved name"; return Status( ErrorCodes::BadValue, errorString.str() ); } } #endif return Status::OK(); }
void Logstream::logLockless( const StringData& s ) { if ( s.size() == 0 ) return; if ( doneSetup == 1717 ) { #if defined(_WIN32) int fd = fileno( logfile ); if ( _isatty( fd ) ) { fflush( logfile ); writeUtf8ToWindowsConsole( s.rawData(), s.size() ); return; } #else if ( isSyslog ) { syslog( LOG_INFO , "%s" , s.rawData() ); return; } #endif if (fwrite(s.rawData(), s.size(), 1, logfile)) { fflush(logfile); } else { int x = errno; cout << "Failed to write to logfile: " << errnoWithDescription(x) << endl; } } else { cout << s; cout.flush(); } }
void FieldRef::parse(const StringData& dottedField) { if (dottedField.size() == 0) { return; } if (_size != 0) { clear(); } // We guarantee that accesses through getPart() will be valid while 'this' is. So we // take a copy. We're going to be "chopping" up the copy into c-strings. _fieldBase.reset(new char[dottedField.size()+1]); dottedField.copyTo( _fieldBase.get(), true ); // Separate the field parts using '.' as a delimiter. char* beg = _fieldBase.get(); char* cur = beg; char* end = beg + dottedField.size(); while (true) { if (cur != end && *cur != '.') { cur++; continue; } appendPart(StringData(beg, cur - beg)); if (cur != end) { *cur = '\0'; beg = ++cur; continue; } break; } }
void BasicArray<T>::to_dot(std::ostream& out, StringData title) const { ref_type ref = get_ref(); if (title.size() != 0) { out << "subgraph cluster_" << ref << " {\n"; out << " label = \"" << title << "\";\n"; out << " color = white;\n"; } out << "n" << std::hex << ref << std::dec << "[shape=none,label=<"; out << "<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\"><TR>\n"; // Header out << "<TD BGCOLOR=\"lightgrey\"><FONT POINT-SIZE=\"7\"> "; out << "0x" << std::hex << ref << std::dec << "<BR/>"; out << "</FONT></TD>\n"; // Values std::size_t n = m_size; for (std::size_t i = 0; i != n; ++i) out << "<TD>" << get(i) << "</TD>\n"; out << "</TR></TABLE>>];\n"; if (title.size() != 0) out << "}\n"; to_dot_parent_edge(out); }
Status WhereMatchExpression::init(StringData dbName, StringData theCode, const BSONObj& scope) { if (dbName.size() == 0) { return Status(ErrorCodes::BadValue, "ns for $where cannot be empty"); } if (theCode.size() == 0) { return Status(ErrorCodes::BadValue, "code for $where cannot be empty"); } _dbName = dbName.toString(); _code = theCode.toString(); _userScope = scope.getOwned(); const string userToken = AuthorizationSession::get(ClientBasic::getCurrent())->getAuthenticatedUserNamesToken(); try { _scope = globalScriptEngine->getPooledScope(_txn, _dbName, "where" + userToken); _func = _scope->createFunction(_code.c_str()); } catch (...) { return exceptionToStatus(); } if (!_func) return Status(ErrorCodes::BadValue, "$where compile error"); return Status::OK(); }
void ObjectStore::set_primary_key_for_object(Group& group, StringData object_type, StringData primary_key) { TableRef table = group.get_table(c_primaryKeyTableName); size_t row = table->find_first_string(c_primaryKeyObjectClassColumnIndex, object_type); #if REALM_ENABLE_SYNC // sync::create_table* functions should have already updated the pk table. if (sync::has_object_ids(group)) { if (primary_key.size() == 0) REALM_ASSERT(row == not_found); else { REALM_ASSERT(row != not_found); REALM_ASSERT(table->get_string(c_primaryKeyPropertyNameColumnIndex, row) == primary_key); } return; } #endif // REALM_ENABLE_SYNC if (row == not_found && primary_key.size()) { row = table->add_empty_row(); table->set_string_unique(c_primaryKeyObjectClassColumnIndex, row, object_type); table->set_string(c_primaryKeyPropertyNameColumnIndex, row, primary_key); return; } // set if changing, or remove if setting to nil if (primary_key.size() == 0) { if (row != not_found) { table->move_last_over(row); } } else { table->set_string(c_primaryKeyPropertyNameColumnIndex, row, primary_key); } }
bool isPathPrefixOf(StringData first, StringData second) { if (first.size() >= second.size()) { return false; } return second.startsWith(first) && second[first.size()] == '.'; }
Status parseNumberFromStringWithBase( const StringData& stringValue, int base, NumberType* result) { typedef ::std::numeric_limits<NumberType> limits; if (base == 1 || base < 0 || base > 36) return Status(ErrorCodes::BadValue, "Invalid base", 0); bool isNegative = false; StringData str = _extractBase(_extractSign(stringValue, &isNegative), base, &base); if (str.empty()) return Status(ErrorCodes::FailedToParse, "No digits"); NumberType n(0); if (isNegative) { if (limits::is_signed) { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) return Status(ErrorCodes::FailedToParse, "Bad digit"); // MSVC: warning C4146: unary minus operator applied to unsigned type, result still unsigned // This code is statically known to be dead when NumberType is unsigned, so the warning is not real #pragma warning(push) #pragma warning(disable:4146) if ((NumberType(limits::min() / base) > n) || ((limits::min() - NumberType(n * base)) > -digitValue)) { #pragma warning(pop) return Status(ErrorCodes::FailedToParse, "Underflow"); } n *= NumberType(base); n -= NumberType(digitValue); } } else { return Status(ErrorCodes::FailedToParse, "Negative value"); } } else { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) return Status(ErrorCodes::FailedToParse, "Bad digit"); if ((NumberType(limits::max() / base) < n) || (NumberType(limits::max() - n * base) < digitValue)) { return Status(ErrorCodes::FailedToParse, "Overflow"); } n *= NumberType(base); n += NumberType(digitValue); } } *result = n; return Status::OK(); }
bool getCanonicalIndexField( StringData fullName, string* out ) { // check if fieldName contains ".$" or ".###" substrings (#=digit) and skip them // however do not skip the first field even if it meets these criteria if ( fullName.find( '.' ) == string::npos ) return false; bool modified = false; StringBuilder buf; for ( size_t i=0; i<fullName.size(); i++ ) { char c = fullName[i]; if ( c != '.' ) { buf << c; continue; } if ( i + 1 == fullName.size() ) { // ends with '.' buf << c; continue; } // check for ".$", skip if present if ( fullName[i+1] == '$' ) { // only do this if its not something like $a if ( i + 2 >= fullName.size() || fullName[i+2] == '.' ) { i++; modified = true; continue; } } // check for ".###" for any number of digits (no letters) if ( isdigit( fullName[i+1] ) ) { size_t j = i; // skip digits while ( j+1 < fullName.size() && isdigit( fullName[j+1] ) ) j++; if ( j+1 == fullName.size() || fullName[j+1] == '.' ) { // only digits found, skip forward i = j; modified = true; continue; } } buf << c; } if ( !modified ) return false; *out = buf.str(); return true; }
std::ostream& MessageEventDetailsEncoder::encode(const MessageEventEphemeral& event, std::ostream& os) { const auto maxLogSizeKB = getMaxLogSizeKB(); const size_t maxLogSize = maxLogSizeKB * 1024; getDateFormatter()(os, event.getDate()); os << ' '; const auto severity = event.getSeverity(); os << severity.toStringDataCompact(); os << ' '; LogComponent component = event.getComponent(); os << component; os << ' '; StringData contextName = event.getContextName(); if (!contextName.empty()) { os << '[' << contextName << "] "; } StringData msg = event.getMessage(); #ifdef _WIN32 // We need to translate embedded Unix style line endings into Windows style endings. std::string tempstr; size_t embeddedNewLine = msg.find('\n'); if (embeddedNewLine != std::string::npos) { tempstr = msg.toString().replace(embeddedNewLine, 1, "\r\n"); embeddedNewLine = tempstr.find('\n', embeddedNewLine + 2); while (embeddedNewLine != std::string::npos) { tempstr = tempstr.replace(embeddedNewLine, 1, "\r\n"); embeddedNewLine = tempstr.find('\n', embeddedNewLine + 2); } msg = tempstr; } #endif if (event.isTruncatable() && msg.size() > maxLogSize) { os << "warning: log line attempted (" << msg.size() / 1024 << "kB) over max size (" << maxLogSizeKB << "kB), printing beginning and end ... "; os << msg.substr(0, maxLogSize / 3); os << " .......... "; os << msg.substr(msg.size() - (maxLogSize / 3)); } else { os << msg; } if (!msg.endsWith(kEOL)) os << kEOL; return os; }
bool operator()(StringData v1, const char* v1_upper, const char* v1_lower, StringData v2, bool = false, bool = false) const { if (v2.is_null() && !v1.is_null()) return false; if (v1.size() == 0 && !v2.is_null()) return true; return search_case_fold(v2, v1_upper, v1_lower, v1.size()) != v2.size(); }
Status userAllowedWriteNS( const StringData& db, const StringData& coll ) { // validity checking if ( db.size() == 0 ) return Status( ErrorCodes::BadValue, "db cannot be blank" ); if ( !NamespaceString::validDBName( db ) ) return Status( ErrorCodes::BadValue, "invalid db name" ); if ( coll.size() == 0 ) return Status( ErrorCodes::BadValue, "collection cannot be blank" ); if ( !NamespaceString::validCollectionName( coll ) ) return Status( ErrorCodes::BadValue, "invalid collection name" ); if ( db.size() + 1 /* dot */ + coll.size() > Namespace::MaxNsColletionLen ) return Status( ErrorCodes::BadValue, str::stream() << "fully qualified namespace " << db << '.' << coll << " is too long " << "(max is " << Namespace::MaxNsColletionLen << " bytes)" ); // check spceial areas if ( db == "system" ) return Status( ErrorCodes::BadValue, "cannot use 'system' database" ); if ( coll.startsWith( "system." ) ) { if ( coll == "system.indexes" ) return Status::OK(); if ( coll == "system.js" ) return Status::OK(); if ( coll == "system.profile" ) return Status::OK(); if ( coll == "system.users" ) return Status::OK(); if ( db == "admin" ) { if ( coll == "system.version" ) return Status::OK(); if ( coll == "system.roles" ) return Status::OK(); if ( coll == "system.new_users" ) return Status::OK(); if ( coll == "system.backup_users" ) return Status::OK(); } if ( db == "local" ) { if ( coll == "system.replset" ) return Status::OK(); } return Status( ErrorCodes::BadValue, str::stream() << "cannot write to '" << db << "." << coll << "'" ); } // some special rules if ( coll.find( ".system." ) != string::npos ) { // this matches old (2.4 and older) behavior, but I'm not sure its a good idea return Status( ErrorCodes::BadValue, str::stream() << "cannot write to '" << db << "." << coll << "'" ); } return Status::OK(); }
bool UpdateIndexData::_startsWith(StringData a, StringData b) const { if (!a.startsWith(b)) return false; // make sure there is a dot or EOL right after if (a.size() == b.size()) return true; return a[b.size()] == '.'; }
// Slow version, used if caller hasn't stored an upper and lower case version bool operator()(StringData v1, StringData v2, bool = false, bool = false) const { if (v2.is_null() && !v1.is_null()) return false; if (v1.size() > v2.size()) return false; std::string v1_upper = case_map(v1, true, IgnoreErrors); std::string v1_lower = case_map(v1, false, IgnoreErrors); return equal_case_fold(v2.suffix(v1.size()), v1_upper.c_str(), v1_lower.c_str()); }
int64_t f_extract(CArrRef var_array, int extract_type /* = EXTR_OVERWRITE */, CStrRef prefix /* = "" */) { bool reference = extract_type & EXTR_REFS; extract_type &= ~EXTR_REFS; VarEnv* v = g_vmContext->getVarEnv(); if (!v) return 0; int count = 0; for (ArrayIter iter(var_array); iter; ++iter) { String name = iter.first(); StringData* nameData = name.get(); switch (extract_type) { case EXTR_SKIP: if (v->lookup(nameData) != NULL) { continue; } break; case EXTR_IF_EXISTS: if (v->lookup(nameData) == NULL) { continue; } break; case EXTR_PREFIX_SAME: if (v->lookup(nameData) != NULL) { name = prefix + "_" + name; } break; case EXTR_PREFIX_ALL: name = prefix + "_" + name; break; case EXTR_PREFIX_INVALID: if (!is_valid_var_name(nameData->data(), nameData->size())) { name = prefix + "_" + name; } break; case EXTR_PREFIX_IF_EXISTS: if (v->lookup(nameData) == NULL) { continue; } name = prefix + "_" + name; break; default: break; } nameData = name.get(); // skip invalid variable names, as in PHP if (!is_valid_var_name(nameData->data(), nameData->size())) { continue; } g_vmContext->setVar(nameData, iter.nvSecond(), reference); count++; } return count; }
// Slow version, used if caller hasn't stored an upper and lower case version bool operator()(StringData v1, StringData v2, bool = false, bool = false) const { if (v1.is_null() != v2.is_null()) return true; if (v1.size() != v2.size()) return true; std::string v1_upper = case_map(v1, true); std::string v1_lower = case_map(v1, false); return !equal_case_fold(v2, v1_upper.c_str(), v1_lower.c_str()); }
std::string createPasswordDigest(const StringData& username, const StringData& clearTextPassword) { md5digest d; { md5_state_t st; md5_init(&st); md5_append(&st, (const md5_byte_t*)username.rawData(), username.size()); md5_append(&st, (const md5_byte_t*)":mongo:", 7); md5_append(&st, (const md5_byte_t*)clearTextPassword.rawData(), clearTextPassword.size()); md5_finish(&st, d); } return digestToString(d); }
// Slow version, used if caller hasn't stored an upper and lower case version bool operator()(StringData v1, StringData v2, bool = false, bool = false) const { if (v2.is_null() && !v1.is_null()) return false; if (v1.size() == 0 && !v2.is_null()) return true; std::string v1_upper = case_map(v1, true, IgnoreErrors); std::string v1_lower = case_map(v1, false, IgnoreErrors); return search_case_fold(v2, v1_upper.c_str(), v1_lower.c_str(), v1.size()) != v2.size(); }
Status parseNumberFromStringWithBase( const StringData& stringValue, int base, NumberType* result) { typedef ::std::numeric_limits<NumberType> limits; if (base == 1 || base < 0 || base > 36) return Status(ErrorCodes::BadValue, "Invalid base", 0); if (stringValue.size() == 0) return Status(ErrorCodes::FailedToParse, "Empty string"); bool isNegative = false; StringData str = _extractBase(_extractSign(stringValue, &isNegative), base, &base); NumberType n(0); if (isNegative) { if (limits::is_signed) { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) return Status(ErrorCodes::FailedToParse, "Bad digit"); if ((NumberType(limits::min() / base) > n) || ((limits::min() - NumberType(n * base)) > -digitValue)) { return Status(ErrorCodes::FailedToParse, "Underflow"); } n *= NumberType(base); n -= NumberType(digitValue); } } else { return Status(ErrorCodes::FailedToParse, "Negative value"); } } else { for (size_t i = 0; i < str.size(); ++i) { NumberType digitValue = NumberType(_digitValue(str[i])); if (int(digitValue) >= base) return Status(ErrorCodes::FailedToParse, "Bad digit"); if ((NumberType(limits::max() / base) < n) || (NumberType(limits::max() - n * base) < digitValue)) { return Status(ErrorCodes::FailedToParse, "Overflow"); } n *= NumberType(base); n += NumberType(digitValue); } } *result = n; return Status::OK(); }
intrusive_ptr<const RCString> RCString::create(StringData s) { const size_t sizeWithNUL = s.size() + 1; const size_t bytesNeeded = sizeof(RCString) + sizeWithNUL; uassert(16493, str::stream() << "Tried to create string longer than " << (BSONObjMaxUserSize/1024/1024) << "MB", bytesNeeded < static_cast<size_t>(BSONObjMaxUserSize)); intrusive_ptr<RCString> ptr = new (bytesNeeded) RCString(); // uses custom operator new ptr->_size = s.size(); char* stringStart = reinterpret_cast<char*>(ptr.get()) + sizeof(RCString); s.copyTo( stringStart, true ); return ptr; }
String HHVM_FUNCTION(serialize, const Variant& value) { switch (value.getType()) { case KindOfUninit: case KindOfNull: return s_Null; case KindOfBoolean: return value.getBoolean() ? s_True : s_False; case KindOfInt64: { StringBuffer sb; sb.append("i:"); sb.append(value.getInt64()); sb.append(';'); return sb.detach(); } case KindOfPersistentString: case KindOfString: { StringData *str = value.getStringData(); StringBuffer sb; sb.append("s:"); sb.append(str->size()); sb.append(":\""); sb.append(str->data(), str->size()); sb.append("\";"); return sb.detach(); } case KindOfResource: return s_Res; case KindOfPersistentArray: case KindOfArray: { ArrayData *arr = value.getArrayData(); if (arr->empty()) { if (arr->isVecArray()) return s_EmptyVecArray; if (arr->isDict()) return s_EmptyDictArray; return s_EmptyArray; } // fall-through } case KindOfDouble: case KindOfObject: { VariableSerializer vs(VariableSerializer::Type::Serialize); return vs.serialize(value, true); } case KindOfRef: case KindOfClass: break; } not_reached(); }
bool ZendArray::exists(CVarRef k) const { TypedValueAccessor tva = k.getTypedAccessor(); if (isIntKey(tva)) return find(getIntKey(tva)); ASSERT(k.isString()); StringData *key = getStringKey(tva); return find(key->data(), key->size(), key->hash()); }
void StringBuffer::absorb(StringBuffer& buf) { if (empty()) { StringData* str = m_str; m_str = buf.m_str; m_buffer = buf.m_buffer; m_len = buf.m_len; m_cap = buf.m_cap; buf.m_str = str; if (str) { buf.m_buffer = (char*)str->data(); buf.m_len = str->size(); buf.m_cap = str->capacity(); } else { buf.m_buffer = 0; buf.m_len = 0; buf.m_cap = 0; } buf.clear(); return; } append(buf.detach()); }
StatusWith<StringData> ClientMetadata::parseApplicationDocument(const BSONObj& doc) { BSONObjIterator i(doc); while (i.more()) { BSONElement e = i.next(); StringData name = e.fieldNameStringData(); // Name is the only required field, and any other fields are simply ignored. if (name == kName) { if (e.type() != String) { return { ErrorCodes::TypeMismatch, str::stream() << "The '" << kApplication << "." << kName << "' field must be a string in the client metadata document"}; } StringData value = e.checkAndGetStringData(); if (value.size() > kMaxApplicationNameByteLength) { return {ErrorCodes::ClientMetadataAppNameTooLarge, str::stream() << "The '" << kApplication << "." << kName << "' field must be less then or equal to " << kMaxApplicationNameByteLength << " bytes in the client metadata document"}; } return {std::move(value)}; } } return {StringData()}; }
std::string Decimal128::_convertToStandardDecimalNotation(StringData coefficient, int exponent) const { if (exponent == 0) { return coefficient.toString(); } else { invariant(exponent < 0); std::string result; int precision = coefficient.size(); // Absolute value of the exponent int significantDecimalDigits = -exponent; bool decimalAppended = false; // Pre-pend 0's before the coefficient as necessary for (int i = precision; i <= significantDecimalDigits; i++) { result += '0'; if (i == precision) { result += '.'; decimalAppended = true; } } // Copy over the digits in the coefficient for (int i = 0; i < precision; i++) { if (precision - i == significantDecimalDigits && !decimalAppended) { result += '.'; } result += coefficient[i]; } return result; } }
Position DocumentStorage::findField(StringData requested) const { int reqSize = requested.size(); // get size calculation out of the way if needed if (_numFields >= HASH_TAB_MIN) { // hash lookup const unsigned bucket = bucketForKey(requested); Position pos = _hashTab[bucket]; while (pos.found()) { const ValueElement& elem = getField(pos); if (elem.nameLen == reqSize && memcmp(requested.rawData(), elem._name, reqSize) == 0) { return pos; } // possible collision pos = elem.nextCollision; } } else { // linear scan for (DocumentStorageIterator it = iteratorAll(); !it.atEnd(); it.advance()) { if (it->nameLen == reqSize && memcmp(requested.rawData(), it->_name, reqSize) == 0) { return it.position(); } } } // if we got here, there's no such field return Position(); }
void Document::hash_combine(size_t &seed) const { for (DocumentStorageIterator it = storage().iterator(); !it.atEnd(); it.advance()) { StringData name = it->nameSD(); boost::hash_range(seed, name.rawData(), name.rawData() + name.size()); it->val.hash_combine(seed); } }
void StringBuffer::absorb(StringBuffer &buf) { if (empty()) { TAINT_OBSERVER_REGISTER_ACCESSED(buf.getTaintDataRefConst()); TAINT_OBSERVER_REGISTER_MUTATED(m_taint_data, dataIgnoreTaint()); StringData* str = m_str; m_str = buf.m_str; m_buffer = buf.m_buffer; m_len = buf.m_len; m_cap = buf.m_cap; buf.m_str = str; if (str) { buf.m_buffer = (char*)str->data(); buf.m_len = str->size(); buf.m_cap = str->capacity(); } else { buf.m_buffer = 0; buf.m_len = 0; buf.m_cap = 0; } buf.reset(); } else { // REGISTER_ACCESSED()/REGISTER_MUTATED() are called by append()/detach() append(buf.detach()); } }