blob: 27645912fc775c4e0b1455c20b803b8db52fb4c6 [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_FORMATS_HLS_SOURCE_STRING_H_
#define MEDIA_FORMATS_HLS_SOURCE_STRING_H_
#include <cstdint>
#include "base/strings/string_piece.h"
#include "base/types/pass_key.h"
#include "media/base/media_export.h"
#include "media/formats/hls/parse_status.h"
namespace media::hls {
struct SourceLineIterator;
class VariableDictionary;
class ResolvedSourceString;
namespace subtle {
// This structure represents contents of a single line in an HLS manifest, not
// including the line ending. This may be the entire line, or a substring of the
// line (clipped at either/both ends).
template <typename Self>
class MEDIA_EXPORT SourceStringBase {
public:
static Self CreateForTesting(base::StringPiece str);
static Self CreateForTesting(size_t line,
size_t column,
base::StringPiece str);
// Returns the 1-based line index of this SourceString within the manifest.
size_t Line() const { return line_; }
// Returns the 1-based index of the first character of this SourceString from
// the start of the line within the manifest.
size_t Column() const { return column_; }
// Returns the contents of this SourceString. This will never include line-end
// characters.
base::StringPiece Str() const { return str_; }
bool Empty() const { return str_.empty(); }
size_t Size() const { return str_.size(); }
Self Substr(size_t pos = 0, size_t count = base::StringPiece::npos) const;
// Consumes this string up to the given count, which may be longer than this
// string. Returns the substring that was consumed.
Self Consume(size_t count = base::StringPiece::npos);
// Finds the first occurrence of the given character, and returns the
// substring prefixing that character. The prefix and character are consumed
// from this string. If the given character does not appear anywhere in this
// string, the entire string is consumed and returned.
Self ConsumeDelimiter(char c);
// Trims whitespace from the start of this SourceString. The only tolerated
// "whitespace" characters are space (' ') and tab ('\t'). Page break ('\f')
// is not tolerated, and carriage return ('\r') and line-feed ('\n') should
// never appear in `SourceString`.
void TrimStart();
// Returns whether this string contains variable substitutions, i.e. is
// different from the original source.
bool ContainsSubstitutions() const;
protected:
SourceStringBase(size_t line, size_t column, base::StringPiece str);
private:
size_t line_;
size_t column_;
base::StringPiece str_;
};
} // namespace subtle
// A `SourceString` is a slice of the original manifest string that may contain
// unresolved variable references.
class MEDIA_EXPORT SourceString final
: public subtle::SourceStringBase<SourceString> {
public:
// Only `SourceLineIterator` may create `SourceString`s.
static SourceString Create(base::PassKey<SourceLineIterator>,
size_t line,
base::StringPiece str) {
return SourceString(line, 1, str);
}
// Produces a `ResolvedSourceString` by bypassing variable substitution.
// This is useful for passing strings that must not contain variables to
// functions consuming strings that may or may not have contained variable
// references.
ResolvedSourceString SkipVariableSubstitution() const;
bool ContainsSubstitutions() const { return false; }
private:
friend SourceStringBase;
SourceString(size_t line, size_t column, base::StringPiece str);
};
// A `ResolvedSourceString` is a string slice that has either undergone or
// skipped variable substitution, and may differ from the original source.
class MEDIA_EXPORT ResolvedSourceString final
: public subtle::SourceStringBase<ResolvedSourceString> {
public:
enum class SubstitutionState {
kNoSubstitutions,
kContainsSubstitutions,
};
// Only `VariableDictionary` or `SourceString` may create
// `ResolvedSourceString`s.
static ResolvedSourceString Create(base::PassKey<VariableDictionary>,
size_t line,
size_t column,
base::StringPiece str,
SubstitutionState substitution_state) {
return ResolvedSourceString(line, column, str, substitution_state);
}
static ResolvedSourceString Create(base::PassKey<SourceString>,
size_t line,
size_t column,
base::StringPiece str) {
return ResolvedSourceString(line, column, str,
SubstitutionState::kNoSubstitutions);
}
bool ContainsSubstitutions() const {
return substitution_state_ == SubstitutionState::kContainsSubstitutions;
}
private:
friend SourceStringBase;
ResolvedSourceString(size_t line,
size_t column,
base::StringPiece str,
SubstitutionState substitution_state =
SubstitutionState::kNoSubstitutions);
SubstitutionState substitution_state_;
};
// Exposes a line-based iteration API over the source text of an HLS manifest.
struct MEDIA_EXPORT SourceLineIterator {
explicit SourceLineIterator(base::StringPiece source);
// Moves this SourceLineIterator to the next line, and returns the contents of
// the current line. Returns `ParseStatusCode::kInvalidEOL` if invalid line
// endings were found, or `ParseStatusCode::kReachedEOF` if no further lines
// exist in the manifest.
ParseStatus::Or<SourceString> Next();
size_t CurrentLineForTesting() const { return current_line_; }
base::StringPiece SourceForTesting() const { return source_; }
private:
size_t current_line_;
base::StringPiece source_;
};
} // namespace media::hls
#endif // MEDIA_FORMATS_HLS_SOURCE_STRING_H_