1 //
2 //   Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 //   Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program 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 this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 #ifdef HAVE_CONFIG_H
20 #include "gnashconfig.h"
21 #endif
22 
23 #ifdef HAVE_DEJAGNU_H
24 #include "dejagnu.h"
25 #endif
26 #include "check.h"
27 
28 #include "noseek_fd_adapter.h"
29 #include "IOChannel.h"
30 #include "tu_file.h"
31 
32 #include <cstdio>
33 #include <iostream>
34 #include <cassert>
35 #include <memory>
36 
37 #include "GnashSystemIOHeaders.h"
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <sstream>
43 #include <limits>
44 
45 using namespace std;
46 
47 #define CHUNK_SIZE 4
48 
49 TestState runtest;
50 
51 static void
dump_buffer(const char * label,char * buf,ssize_t size,ostream & os)52 dump_buffer(const char* label, char* buf, ssize_t size, ostream& os)
53 {
54 	os << label << ":" << endl;
55 	for (ssize_t i=0; i<size; i++) {
56 		os << '[' << buf[i] << ']';
57 	}
58 
59 }
60 
61 
62 static bool
compare_reads(gnash::IOChannel * reader,int fd,const char * first,const char * second)63 compare_reads(gnash::IOChannel* reader, int fd, const char* first, const char* second)
64 {
65 	char buf[CHUNK_SIZE];
66 	char buf2[CHUNK_SIZE];
67 
68 	stringstream ss;
69 
70 
71 	size_t consumed = 0;
72 
73 	for(;;)
74 	{
75 		ssize_t sz1 = reader->read(buf, CHUNK_SIZE);
76 		ssize_t sz2 = read(fd, buf2, CHUNK_SIZE);
77 
78 		if ( sz1 != sz2 )
79 		{
80 			ss << "Different read size from " << first
81 				<< " (" << sz1 << ") and " << second
82 				<< " (" << sz2 << ") file";
83 			runtest.fail(ss.str());
84 			dump_buffer("wrapped", buf, sz1, cout);
85 			dump_buffer("raw", buf2, sz2, cout);
86 			return false;
87 		}
88 
89 		if ( sz1 <= 0 ) {
90 			break;
91 		}
92 
93 		if ( memcmp(buf, buf2, sz1) )
94 		{
95 			ss << "Different read content from " << first
96 				<< " and " << second << " file";
97 			runtest.fail(ss.str());
98 			dump_buffer("wrapped", buf, sz1, cout);
99 			dump_buffer("raw", buf2, sz2, cout);
100 			return false;
101 		}
102 
103 		consumed+=sz1;
104 	}
105 
106 	if ( consumed == 0 )
107 	{
108 		runtest.fail("No bytes read from either " + string(first) + " or " + string(second) + " file");
109 		return false;
110 	}
111 
112 	if ( ! reader->eof() )
113 	{
114 		ss << "tu_file not at EOF at end of read";
115 		runtest.fail(ss.str());
116 		return false;
117 	}
118 
119 	ss << "compared " << consumed << " bytes from "
120 		<< first << " and " << second;
121 
122 	runtest.pass(ss.str());
123 	return true;
124 
125 
126 	return true;
127 
128 }
129 
130 TRYMAIN(_runtest);
131 int
trymain(int,char **)132 trymain(int /*argc*/, char** /*argv*/)
133 {
134 	const char* input = INPUT; // Should be the path to this file
135 	const char* cachename = "NoSeekFileTestCache";
136 
137 	int fd = open(input, O_RDONLY);
138 	int raw = open(input, O_RDONLY);
139 
140 	if (fd < 0 || raw < 0) {
141 	    runtest.fail("Unable to open input file");
142 	}
143 
144 	dup2(fd, 0);
145 	close(fd);
146 
147 	std::unique_ptr<gnash::IOChannel> reader(gnash::noseek_fd_adapter::make_stream(0, cachename));
148 	assert(reader);
149 
150 	compare_reads(reader.get(), raw, "wrapped", "raw");
151 
152 	lseek(raw, 0, SEEK_SET);
153 	reader->seek(0);
154 	compare_reads(reader.get(), raw, "wrapped-rewind", "raw-rewind");
155 
156 
157     FILE* f = std::fopen(cachename, "r");
158     std::unique_ptr<gnash::IOChannel> orig = gnash::makeFileChannel(f, false);
159 	lseek(raw, 0, SEEK_SET);
160 	compare_reads(orig.get(), raw, "cache", "raw");
161 	close(raw);
162 
163 
164     if (sizeof(size_t) != sizeof(std::streamoff)) {
165         std::streampos pos = std::numeric_limits<size_t>::max();
166         pos += orig->size() / 2;
167         // Check that seek() handles integer overflow situations gracefully.
168         if (orig->seek(pos)) {
169             runtest.fail("Successfully sought to an invalid position.");
170         } else {
171             runtest.pass("Gracefully handled invalid seek.");
172         }
173     }
174 
175 
176 
177 	return 0;
178 }
179 
180