1/* 2 * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "JSStringJoiner.h" 28 29#include "ExceptionHelpers.h" 30#include "JSScope.h" 31#include "JSString.h" 32#include "Operations.h" 33#include <wtf/text/StringImpl.h> 34 35namespace JSC { 36 37// The destination is 16bits, at least one string is 16 bits. 38static inline void appendStringToData(UChar*& data, const String& string) 39{ 40 if (string.isNull()) 41 return; 42 43 unsigned length = string.length(); 44 const StringImpl* stringImpl = string.impl(); 45 46 if (stringImpl->is8Bit()) { 47 for (unsigned i = 0; i < length; ++i) { 48 *data = stringImpl->characters8()[i]; 49 ++data; 50 } 51 } else { 52 for (unsigned i = 0; i < length; ++i) { 53 *data = stringImpl->characters16()[i]; 54 ++data; 55 } 56 } 57} 58 59// If the destination is 8bits, we know every string has to be 8bit. 60static inline void appendStringToData(LChar*& data, const String& string) 61{ 62 if (string.isNull()) 63 return; 64 ASSERT(string.is8Bit()); 65 66 unsigned length = string.length(); 67 const StringImpl* stringImpl = string.impl(); 68 69 for (unsigned i = 0; i < length; ++i) { 70 *data = stringImpl->characters8()[i]; 71 ++data; 72 } 73} 74 75template<typename CharacterType> 76static inline PassRefPtr<StringImpl> joinStrings(const Vector<String>& strings, const String& separator, unsigned outputLength) 77{ 78 ASSERT(outputLength); 79 80 CharacterType* data; 81 RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data); 82 if (!outputStringImpl) 83 return PassRefPtr<StringImpl>(); 84 85 const String firstString = strings.first(); 86 appendStringToData(data, firstString); 87 88 for (size_t i = 1; i < strings.size(); ++i) { 89 appendStringToData(data, separator); 90 appendStringToData(data, strings[i]); 91 } 92 93 ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length())); 94 return outputStringImpl.release(); 95} 96 97JSValue JSStringJoiner::join(ExecState* exec) 98{ 99 if (!m_isValid) 100 return throwOutOfMemoryError(exec); 101 102 if (!m_strings.size()) 103 return jsEmptyString(exec); 104 105 Checked<unsigned, RecordOverflow> separatorLength = m_separator.length(); 106 // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1). 107 ASSERT(m_strings.size() > 0); 108 Checked<unsigned, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1); 109 Checked<unsigned, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength; 110 111 unsigned finalSize; 112 if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow) 113 return throwOutOfMemoryError(exec); 114 115 if (!outputStringSize) 116 return jsEmptyString(exec); 117 118 RefPtr<StringImpl> outputStringImpl; 119 if (m_is8Bits) 120 outputStringImpl = joinStrings<LChar>(m_strings, m_separator, finalSize); 121 else 122 outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize); 123 124 if (!outputStringImpl) 125 return throwOutOfMemoryError(exec); 126 127 return JSString::create(exec->vm(), outputStringImpl.release()); 128} 129 130} 131