1/* MiniDLNA media server
2 * Copyright (C) 2009  Justin Maggard
3 *
4 * This file is part of MiniDLNA.
5 *
6 * MiniDLNA is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * MiniDLNA is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
17 */
18#include "config.h"
19#ifdef TIVO_SUPPORT
20#include <stdlib.h>
21#include <stdint.h>
22#include <string.h>
23#include <ctype.h>
24#include <unistd.h>
25#include <fcntl.h>
26#include <sys/types.h>
27#include <sqlite3.h>
28#include "tivo_utils.h"
29
30/* This function based on byRequest */
31char *
32decodeString(char *string, int inplace)
33{
34	if( !string )
35		return NULL;
36	int alloc = (int)strlen(string)+1;
37	char *ns = NULL;
38	unsigned char in;
39	int strindex=0;
40	long hex;
41
42	if( !inplace )
43	{
44		if( !(ns = malloc(alloc)) )
45			return NULL;
46	}
47
48	while(--alloc > 0)
49	{
50		in = *string;
51		if((in == '%') && isxdigit(string[1]) && isxdigit(string[2]))
52		{
53			/* this is two hexadecimal digits following a '%' */
54			char hexstr[3];
55			char *ptr;
56			hexstr[0] = string[1];
57			hexstr[1] = string[2];
58			hexstr[2] = 0;
59
60			hex = strtol(hexstr, &ptr, 16);
61
62			in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
63			if( inplace )
64			{
65				*string = in;
66				memmove(string+1, string+3, alloc-2);
67			}
68			else
69			{
70				string+=2;
71			}
72			alloc-=2;
73		}
74		if( !inplace )
75			ns[strindex++] = in;
76		string++;
77	}
78	if( inplace )
79	{
80		free(ns);
81		return string;
82	}
83	else
84	{
85		ns[strindex] = '\0'; /* terminate it */
86		return ns;
87	}
88}
89
90/* These next functions implement a repeatable random function with a user-provided seed */
91static int
92seedRandomByte(uint32_t seed)
93{
94	unsigned char t;
95
96	if( !sqlite3Prng.isInit )
97	{
98		int i;
99		char k[256];
100		sqlite3Prng.j = 0;
101		sqlite3Prng.i = 0;
102		memset(&k, '\0', sizeof(k));
103		memcpy(&k, &seed, 4);
104		for(i=0; i<256; i++)
105			sqlite3Prng.s[i] = i;
106		for(i=0; i<256; i++)
107		{
108			sqlite3Prng.j += sqlite3Prng.s[i] + k[i];
109			t = sqlite3Prng.s[sqlite3Prng.j];
110			sqlite3Prng.s[sqlite3Prng.j] = sqlite3Prng.s[i];
111			sqlite3Prng.s[i] = t;
112		}
113		sqlite3Prng.isInit = 1;
114	}
115	/* Generate and return single random byte */
116	sqlite3Prng.i++;
117	t = sqlite3Prng.s[sqlite3Prng.i];
118	sqlite3Prng.j += t;
119	sqlite3Prng.s[sqlite3Prng.i] = sqlite3Prng.s[sqlite3Prng.j];
120	sqlite3Prng.s[sqlite3Prng.j] = t;
121	t += sqlite3Prng.s[sqlite3Prng.i];
122
123	return sqlite3Prng.s[t];
124}
125
126static void
127seedRandomness(int n, void *pbuf, uint32_t seed)
128{
129	unsigned char *zbuf = pbuf;
130
131	while( n-- )
132		*(zbuf++) = seedRandomByte(seed);
133}
134
135void
136TiVoRandomSeedFunc(sqlite3_context *context, int argc, sqlite3_value **argv)
137{
138	int64_t r, seed;
139
140	if( argc != 1 || sqlite3_value_type(argv[0]) != SQLITE_INTEGER )
141		return;
142	seed = sqlite3_value_int64(argv[0]);
143	seedRandomness(sizeof(r), &r, seed);
144	sqlite3_result_int64(context, r);
145}
146
147int
148is_tivo_file(const char *path)
149{
150	unsigned char buf[5];
151	unsigned char hdr[5] = { 'T','i','V','o','\0' };
152	int fd;
153
154	/* read file header */
155	fd = open(path, O_RDONLY);
156	if( fd < 0 )
157		return 0;
158	if( read(fd, buf, 5) < 5 )
159		buf[0] = 'X';
160	close(fd);
161
162	return !memcmp(buf, hdr, 5);
163}
164
165#endif
166