blob: b8307b7b5bfd959ecc67c1d04fdfb077af7091ca [file] [log] [blame] [edit]
// Copyright 2015 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <base/check_op.h>
#include <brillo/streams/stream_utils.h>
#include <algorithm>
#include <limits>
#include <memory>
#include <utility>
#include <vector>
#include <base/functional/bind.h>
#include <brillo/message_loops/message_loop.h>
#include <brillo/streams/stream_errors.h>
namespace brillo {
namespace stream_utils {
bool ErrorStreamClosed(const base::Location& location, ErrorPtr* error) {
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kStreamClosed, "Stream is closed");
return false;
}
bool ErrorOperationNotSupported(const base::Location& location,
ErrorPtr* error) {
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kOperationNotSupported,
"Stream operation not supported");
return false;
}
bool ErrorReadPastEndOfStream(const base::Location& location, ErrorPtr* error) {
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kPartialData, "Reading past the end of stream");
return false;
}
bool ErrorOperationTimeout(const base::Location& location, ErrorPtr* error) {
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kTimeout, "Operation timed out");
return false;
}
bool CheckInt64Overflow(const base::Location& location,
uint64_t position,
int64_t offset,
ErrorPtr* error) {
if (offset < 0) {
// Subtracting the offset. Make sure we do not underflow.
uint64_t unsigned_offset = static_cast<uint64_t>(-offset);
if (position >= unsigned_offset)
return true;
} else {
// Adding the offset. Make sure we do not overflow unsigned 64 bits first.
if (position <= std::numeric_limits<uint64_t>::max() - offset) {
// We definitely will not overflow the unsigned 64 bit integer.
// Now check that we end up within the limits of signed 64 bit integer.
uint64_t new_position = position + offset;
uint64_t max = std::numeric_limits<int64_t>::max();
if (new_position <= max)
return true;
}
}
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kInvalidParameter,
"The stream offset value is out of range");
return false;
}
bool CalculateStreamPosition(const base::Location& location,
int64_t offset,
Stream::Whence whence,
uint64_t current_position,
uint64_t stream_size,
uint64_t* new_position,
ErrorPtr* error) {
uint64_t pos = 0;
switch (whence) {
case Stream::Whence::FROM_BEGIN:
pos = 0;
break;
case Stream::Whence::FROM_CURRENT:
pos = current_position;
break;
case Stream::Whence::FROM_END:
pos = stream_size;
break;
default:
Error::AddTo(error, location, errors::stream::kDomain,
errors::stream::kInvalidParameter,
"Invalid stream position whence");
return false;
}
if (!CheckInt64Overflow(location, pos, offset, error))
return false;
*new_position = static_cast<uint64_t>(pos + offset);
return true;
}
} // namespace stream_utils
} // namespace brillo