stream_utils.cc revision 1b79239785bf964fd5f1a607a6ed9c9bbb57a4b1
11e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// Copyright 2015 The Chromium OS Authors. All rights reserved.
21e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// Use of this source code is governed by a BSD-style license that can be
31e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko// found in the LICENSE file.
41e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
51e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko#include <chromeos/streams/stream_utils.h>
61e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
71e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko#include <limits>
81e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
91e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko#include <chromeos/streams/stream_errors.h>
101e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
111e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkonamespace chromeos {
121e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkonamespace stream_utils {
131e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
141e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorStreamClosed(const tracked_objects::Location& location,
151e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                       ErrorPtr* error) {
161e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  Error::AddTo(error,
171e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               location,
181e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kDomain,
191e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kStreamClosed,
201e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               "Stream is closed");
211e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  return false;
221e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}
231e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
241e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorOperationNotSupported(const tracked_objects::Location& location,
251e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                                ErrorPtr* error) {
261e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  Error::AddTo(error,
271e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               location,
281e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kDomain,
291e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kOperationNotSupported,
301e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               "Stream operation not supported");
311e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  return false;
321e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}
331e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
341e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool ErrorReadPastEndOfStream(const tracked_objects::Location& location,
351e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                              ErrorPtr* error) {
361e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  Error::AddTo(error,
371e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               location,
381e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kDomain,
391e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kPartialData,
401e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               "Reading past the end of stream");
411e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  return false;
421e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}
431e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
441b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenkobool ErrorOperationTimeout(const tracked_objects::Location& location,
451b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko                           ErrorPtr* error) {
461b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko  Error::AddTo(error,
471b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko               location,
481b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko               errors::stream::kDomain,
491b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko               errors::stream::kTimeout,
501b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko               "Operation timed out");
511b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko  return false;
521b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko}
531b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko
541b79239785bf964fd5f1a607a6ed9c9bbb57a4b1Alex Vakulenko
551e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool CheckInt64Overflow(const tracked_objects::Location& location,
561e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                        uint64_t position,
571e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                        int64_t offset,
581e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                        ErrorPtr* error) {
591e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  if (offset < 0) {
601e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    // Subtracting the offset. Make sure we do not underflow.
611e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    uint64_t unsigned_offset = static_cast<uint64_t>(-offset);
621e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    if (position >= unsigned_offset)
631e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      return true;
641e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  } else {
651e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    // Adding the offset. Make sure we do not overflow unsigned 64 bits first.
661e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    if (position <= std::numeric_limits<uint64_t>::max() - offset) {
671e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      // We definitely will not overflow the unsigned 64 bit integer.
681e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      // Now check that we end up within the limits of signed 64 bit integer.
691e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      uint64_t new_position = position + offset;
701e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      uint64_t max = std::numeric_limits<int64_t>::max();
711e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      if (new_position <= max)
721e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko        return true;
731e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    }
741e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  }
751e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  Error::AddTo(error,
761e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               location,
771e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kDomain,
781e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               errors::stream::kInvalidParameter,
791e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko               "The stream offset value is out of range");
801e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  return false;
811e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}
821e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
831e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenkobool CalculateStreamPosition(const tracked_objects::Location& location,
841e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             int64_t offset,
851e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             Stream::Whence whence,
861e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             uint64_t current_position,
871e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             uint64_t stream_size,
881e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             uint64_t* new_position,
891e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                             ErrorPtr* error) {
901e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  uint64_t pos = 0;
911e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  switch (whence) {
921e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    case Stream::Whence::FROM_BEGIN:
931e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      pos = 0;
941e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      break;
951e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
961e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    case Stream::Whence::FROM_CURRENT:
971e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      pos = current_position;
981e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      break;
991e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
1001e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    case Stream::Whence::FROM_END:
1011e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      pos = stream_size;
1021e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      break;
1031e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
1041e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    default:
1051e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      Error::AddTo(error,
1061e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                   location,
1071e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                   errors::stream::kDomain,
1081e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                   errors::stream::kInvalidParameter,
1091e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko                   "Invalid stream position whence");
1101e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko      return false;
1111e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  }
1121e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
1131e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  if (!CheckInt64Overflow(location, pos, offset, error))
1141e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko    return false;
1151e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
1161e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  *new_position = static_cast<uint64_t>(pos + offset);
1171e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko  return true;
1181e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}
1191e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko
1201e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}  // namespace stream_utils
1211e582b39cf77c6ec0ed908153b40e3875a30a2e5Alex Vakulenko}  // namespace chromeos
122