This repository has been archived by the owner on Jan 29, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
icy.cc
142 lines (116 loc) · 2.84 KB
/
icy.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
* icy - protocol functions and constants - implementation
* Copyright(c) 2003-2006 of wave++ (Yuri D'Elia) <[email protected]>
* Distributed under GNU LGPL without ANY warranty.
*/
// interface
#include "icy.hh"
using std::ostream;
using std::map;
using std::string;
using std::cout;
// system headers
#include <stdexcept>
// c system headers
#include <string.h>
// implementation
namespace ICY
{
namespace Proto
{
// global definitions
const char* reqMeta = "icy-metadata: 1";
const char* notice1 = "icy-notice1";
const char* notice2 = "icy-notice2";
const char* title = "icy-name";
const char* genre = "icy-genre";
const char* url = "icy-url";
const char* br = "icy-br";
const char* metaint = "icy-metaint";
const char* mTitle = "StreamTitle";
// local constants
const char vaStart[] = "='";
const size_t vaStartSz = sizeof(vaStart) / sizeof(*vaStart) - 1;
const char vaEnd[] = "';";
const size_t vaEndSz = sizeof(vaEnd) / sizeof(*vaEnd) - 1;
}
Reader::Reader(Socket& in, const size_t bufSz, const size_t metaSz)
: in(in), bufSz(bufSz), mBufSz(metaSz)
{
buf = new char[bufSz];
mBuf = new char[mBufSz];
}
Reader::~Reader()
{
delete []buf;
delete []mBuf;
}
size_t
Reader::dup(std::ostream* out, const size_t size, bool dup)
{
size_t r(0);
while(r != size)
{
size_t p(in.read(buf, (bufSz + r > size)? size - r: bufSz));
if(!p)
break;
if(out)
out->write(buf, p);
if(dup)
{
// check for writing errors, but do not throw exceptions: SIGPIPE
// should be generated already.
cout.write(buf, p);
if(!cout)
dup = false;
else
cout.flush();
}
r += p;
}
return r;
}
size_t
Reader::readMeta(map<string, string>& meta)
{
// read the first byte containing the lenght
char b;
in.readn(&b, sizeof(b));
size_t lenght(b * Proto::metaMul);
if(lenght > Proto::metaSz)
throw std::runtime_error("metadata stream lenght invalid");
// metadata could be empty
if(lenght)
{
in.readn(mBuf, lenght);
// check for NULL termination
if(mBuf[lenght - 1])
throw std::runtime_error("invalid metadata stream");
char* p(mBuf);
char* n;
/*
* Now we parse the data. They're in the form name='value';name....
* Unfortunatly, looking at the ICEcast and AMPLE code I do not
* see any escape sequence for values containing "';" so I merely
* look for terminators. Needless to say this is UGLY.
*/
while(*p)
{
// variable name
n = strstr(p, Proto::vaStart);
if(!n)
break;
string name(p, n);
p = n + Proto::vaStartSz;
// value
n = strstr(p, Proto::vaEnd);
if(!n)
break;
string value(p, n);
p = n + Proto::vaEndSz;
meta.insert(std::make_pair(name, value));
}
}
return lenght;
}
}