1/* 2 * libjingle 3 * Copyright 2004--2005, Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "talk/base/transformadapter.h" 29 30#include <cstring> 31 32#include "talk/base/common.h" 33 34namespace talk_base { 35 36/////////////////////////////////////////////////////////////////////////////// 37 38TransformAdapter::TransformAdapter(StreamInterface * stream, 39 TransformInterface * transform, 40 bool direction_read) 41 : StreamAdapterInterface(stream), transform_(transform), 42 direction_read_(direction_read), state_(ST_PROCESSING), len_(0) { 43} 44 45TransformAdapter::~TransformAdapter() { 46 TransformAdapter::Close(); 47 delete transform_; 48} 49 50StreamResult 51TransformAdapter::Read(void * buffer, size_t buffer_len, 52 size_t * read, int * error) { 53 if (!direction_read_) 54 return SR_EOS; 55 56 while (state_ != ST_ERROR) { 57 if (state_ == ST_COMPLETE) 58 return SR_EOS; 59 60 // Buffer more data 61 if ((state_ == ST_PROCESSING) && (len_ < sizeof(buffer_))) { 62 size_t subread; 63 StreamResult result = StreamAdapterInterface::Read( 64 buffer_ + len_, 65 sizeof(buffer_) - len_, 66 &subread, 67 &error_); 68 if (result == SR_BLOCK) { 69 return SR_BLOCK; 70 } else if (result == SR_ERROR) { 71 state_ = ST_ERROR; 72 break; 73 } else if (result == SR_EOS) { 74 state_ = ST_FLUSHING; 75 } else { 76 len_ += subread; 77 } 78 } 79 80 // Process buffered data 81 size_t in_len = len_; 82 size_t out_len = buffer_len; 83 StreamResult result = transform_->Transform(buffer_, &in_len, 84 buffer, &out_len, 85 (state_ == ST_FLUSHING)); 86 ASSERT(result != SR_BLOCK); 87 if (result == SR_EOS) { 88 // Note: Don't signal SR_EOS this iteration, unless out_len is zero 89 state_ = ST_COMPLETE; 90 } else if (result == SR_ERROR) { 91 state_ = ST_ERROR; 92 error_ = -1; // TODO: propagate error 93 break; 94 } else if ((out_len == 0) && (state_ == ST_FLUSHING)) { 95 // If there is no output AND no more input, then something is wrong 96 state_ = ST_ERROR; 97 error_ = -1; // TODO: better error code? 98 break; 99 } 100 101 len_ -= in_len; 102 if (len_ > 0) 103 memmove(buffer_, buffer_ + in_len, len_); 104 105 if (out_len == 0) 106 continue; 107 108 if (read) 109 *read = out_len; 110 return SR_SUCCESS; 111 } 112 113 if (error) 114 *error = error_; 115 return SR_ERROR; 116} 117 118StreamResult 119TransformAdapter::Write(const void * data, size_t data_len, 120 size_t * written, int * error) { 121 if (direction_read_) 122 return SR_EOS; 123 124 size_t bytes_written = 0; 125 while (state_ != ST_ERROR) { 126 if (state_ == ST_COMPLETE) 127 return SR_EOS; 128 129 if (len_ < sizeof(buffer_)) { 130 // Process buffered data 131 size_t in_len = data_len; 132 size_t out_len = sizeof(buffer_) - len_; 133 StreamResult result = transform_->Transform(data, &in_len, 134 buffer_ + len_, &out_len, 135 (state_ == ST_FLUSHING)); 136 137 ASSERT(result != SR_BLOCK); 138 if (result == SR_EOS) { 139 // Note: Don't signal SR_EOS this iteration, unless no data written 140 state_ = ST_COMPLETE; 141 } else if (result == SR_ERROR) { 142 ASSERT(false); // When this happens, think about what should be done 143 state_ = ST_ERROR; 144 error_ = -1; // TODO: propagate error 145 break; 146 } 147 148 len_ = out_len; 149 bytes_written = in_len; 150 } 151 152 size_t pos = 0; 153 while (pos < len_) { 154 size_t subwritten; 155 StreamResult result = StreamAdapterInterface::Write(buffer_ + pos, 156 len_ - pos, 157 &subwritten, 158 &error_); 159 if (result == SR_BLOCK) { 160 ASSERT(false); // TODO: we should handle this 161 return SR_BLOCK; 162 } else if (result == SR_ERROR) { 163 state_ = ST_ERROR; 164 break; 165 } else if (result == SR_EOS) { 166 state_ = ST_COMPLETE; 167 break; 168 } 169 170 pos += subwritten; 171 } 172 173 len_ -= pos; 174 if (len_ > 0) 175 memmove(buffer_, buffer_ + pos, len_); 176 177 if (bytes_written == 0) 178 continue; 179 180 if (written) 181 *written = bytes_written; 182 return SR_SUCCESS; 183 } 184 185 if (error) 186 *error = error_; 187 return SR_ERROR; 188} 189 190void 191TransformAdapter::Close() { 192 if (!direction_read_ && (state_ == ST_PROCESSING)) { 193 state_ = ST_FLUSHING; 194 do { 195 Write(0, 0, NULL, NULL); 196 } while (state_ == ST_FLUSHING); 197 } 198 state_ = ST_COMPLETE; 199 StreamAdapterInterface::Close(); 200} 201 202} // namespace talk_base 203