1use strict;
2use warnings;
3
4package Data::ParseBinary::Stream::StringRefReader;
5our @ISA = qw{Data::ParseBinary::Stream::Reader};
6
7__PACKAGE__->_registerStreamType("StringRef");
8
9sub new {
10    my ($class, $stringref) = @_;
11    my $self = {
12        data => $stringref,
13        location => 0,
14        length => length($$stringref),
15    };
16    return bless $self, $class;
17}
18
19sub ReadBytes {
20    my ($self, $count) = @_;
21    die "not enought bytes in stream" if $self->{location} + $count > $self->{length};
22    my $data = substr(${ $self->{data} }, $self->{location}, $count);
23    $self->{location} += $count;
24    return $data;
25}
26
27sub ReadBits {
28    my ($self, $bitcount) = @_;
29    return $self->_readBitsForByteStream($bitcount);
30}
31
32sub tell {
33    my $self = shift;
34    return $self->{location};
35}
36
37sub seek {
38    my ($self, $newpos) = @_;
39    die "can not seek past string's end" if $newpos > $self->{length};
40    $self->{location} = $newpos;
41}
42
43sub isBitStream { return 0 };
44
45package Data::ParseBinary::Stream::StringReader;
46our @ISA = qw{Data::ParseBinary::Stream::StringRefReader};
47
48__PACKAGE__->_registerStreamType("String");
49
50sub new {
51    my ($class, $string) = @_;
52    return $class->SUPER::new(\$string);
53}
54
55package Data::ParseBinary::Stream::StringRefWriter;
56our @ISA = qw{Data::ParseBinary::Stream::Writer};
57
58__PACKAGE__->_registerStreamType("StringRef");
59
60sub new {
61    my ($class, $source) = @_;
62    if (not defined $source) {
63        my $data = '';
64        $source = \$data;
65    }
66    my $self = {
67        data => $source,
68        offset => 0, # minus bytes from the end
69    };
70    return bless $self, $class;
71}
72
73sub tell {
74    my $self = shift;
75    return length(${ $self->{data} }) - $self->{offset};
76}
77
78sub seek {
79    my ($self, $newpos) = @_;
80    if ($newpos > length(${ $self->{data} })) {
81        $self->{offset} = 0;
82        ${ $self->{data} } .= "\0" x ($newpos - length(${ $self->{data} }))
83    } else {
84        $self->{offset} = length(${ $self->{data} }) - $newpos;
85    }
86}
87
88sub WriteBytes {
89    my ($self, $data) = @_;
90    if ($self->{offset} == 0) {
91        ${ $self->{data} } .= $data;
92        return length ${ $self->{data} };
93    }
94    substr(${ $self->{data} }, -$self->{offset}, length($data), $data);
95    if ($self->{offset} <= length($data)) {
96        $self->{offset} = 0;
97    } else {
98        $self->{offset} = $self->{offset} - length($data);
99    }
100    return length(${ $self->{data} }) - $self->{offset};
101}
102
103sub WriteBits {
104    my ($self, $bitdata) = @_;
105    return $self->_writeBitsForByteStream($bitdata);
106}
107
108sub Flush {
109    my $self = shift;
110    return $self->{data};
111}
112
113sub isBitStream { return 0 };
114
115package Data::ParseBinary::Stream::StringWriter;
116our @ISA = qw{Data::ParseBinary::Stream::StringRefWriter};
117
118__PACKAGE__->_registerStreamType("String");
119
120sub new {
121    my ($class, $source) = @_;
122    $source = '' unless defined $source;
123    return $class->SUPER::new(\$source);
124}
125
126sub Flush {
127    my $self = shift;
128    my $data = $self->SUPER::Flush();
129    return $$data;
130}
131
132
1331;