diff options
Diffstat (limited to 'dep/libmpq/bindings')
| -rw-r--r-- | dep/libmpq/bindings/Makefile.am | 6 | ||||
| -rw-r--r-- | dep/libmpq/bindings/d/Makefile.am | 6 | ||||
| -rw-r--r-- | dep/libmpq/bindings/d/dsss.conf | 2 | ||||
| -rw-r--r-- | dep/libmpq/bindings/d/mpq.d | 318 | ||||
| -rw-r--r-- | dep/libmpq/bindings/python/Makefile.am | 5 | ||||
| -rw-r--r-- | dep/libmpq/bindings/python/mpq-info | 16 | ||||
| -rw-r--r-- | dep/libmpq/bindings/python/mpq.py | 322 |
7 files changed, 0 insertions, 675 deletions
diff --git a/dep/libmpq/bindings/Makefile.am b/dep/libmpq/bindings/Makefile.am deleted file mode 100644 index b9fefe306ef..00000000000 --- a/dep/libmpq/bindings/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -# any directories which should be built and installed. -SUBDIRS = d - -if HAVE_PYTHON -SUBDIRS += python -endif diff --git a/dep/libmpq/bindings/d/Makefile.am b/dep/libmpq/bindings/d/Makefile.am deleted file mode 100644 index 4de7285ae51..00000000000 --- a/dep/libmpq/bindings/d/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -# minimum required automake 1.6 -AUTOMAKE_OPTIONS = 1.6 - -# install D binding to /usr/include/d by default -libmpq_includedir = $(includedir)/d -libmpq_include_HEADERS = mpq.d diff --git a/dep/libmpq/bindings/d/dsss.conf b/dep/libmpq/bindings/d/dsss.conf deleted file mode 100644 index 252482c4933..00000000000 --- a/dep/libmpq/bindings/d/dsss.conf +++ /dev/null @@ -1,2 +0,0 @@ -[mpq.d] -type=sourcelibrary diff --git a/dep/libmpq/bindings/d/mpq.d b/dep/libmpq/bindings/d/mpq.d deleted file mode 100644 index d72c2d2a986..00000000000 --- a/dep/libmpq/bindings/d/mpq.d +++ /dev/null @@ -1,318 +0,0 @@ -/* - * mpq.d -- D programming language module for libmpq - * - * Copyright (c) 2008 Georg Lukas <georg@op-co.de> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * This module is written to support Phobos. Patches to allow binding to - * Tango are welcome. - */ - -module mpq; - -/* the following pragma does not work on DMD/Linux, generates a warning on - * GDC/Linux and has not been tested on Windows. Commented out for now. */ -// pragma(lib, "libmpq"); - -import std.string; // for format() and toStringz() -import std.traits; // for ParameterTypeTuple!() - -/* XXX: this assumes that libmpq is compiled with Large File Support on */ -alias long off_t; - -/* libmpq error return values */ -const LIBMPQ_ERROR_OPEN = -1; /* open error on file. */ -const LIBMPQ_ERROR_CLOSE = -2; /* close error on file. */ -const LIBMPQ_ERROR_SEEK = -3; /* lseek error on file. */ -const LIBMPQ_ERROR_READ = -4; /* read error on file. */ -const LIBMPQ_ERROR_WRITE = -5; /* write error on file. */ -const LIBMPQ_ERROR_MALLOC = -6; /* memory allocation error. */ -const LIBMPQ_ERROR_FORMAT = -7; /* format errror. */ -const LIBMPQ_ERROR_NOT_INITIALIZED = -8; /* init() wasn't called. */ -const LIBMPQ_ERROR_SIZE = -9; /* buffer size is to small. */ -const LIBMPQ_ERROR_EXIST = -10; /* file or block does not exist in archive. */ -const LIBMPQ_ERROR_DECRYPT = -11; /* we don't know the decryption seed. */ -const LIBMPQ_ERROR_UNPACK = -12; /* error on unpacking file. */ - -/** libmpq internal meta-data for an archive */ -extern struct mpq_archive_s; - -extern(C) { - -/* libmpq__generic information about library. */ -char *libmpq__version(); - -/* libmpq__generic mpq archive information. */ -int libmpq__archive_open(mpq_archive_s **mpq_archive, char *mpq_filename, off_t archive_offset); -int libmpq__archive_close(mpq_archive_s *mpq_archive); -int libmpq__archive_packed_size(mpq_archive_s *mpq_archive, off_t *packed_size); -int libmpq__archive_unpacked_size(mpq_archive_s *mpq_archive, off_t *unpacked_size); -int libmpq__archive_offset(mpq_archive_s *mpq_archive, off_t *offset); -int libmpq__archive_version(mpq_archive_s *mpq_archive, uint *version_); -int libmpq__archive_files(mpq_archive_s *mpq_archive, uint *files); - -/* libmpq__generic file processing functions. */ -int libmpq__file_packed_size(mpq_archive_s *mpq_archive, uint file_number, off_t *packed_size); -int libmpq__file_unpacked_size(mpq_archive_s *mpq_archive, uint file_number, off_t *unpacked_size); -int libmpq__file_offset(mpq_archive_s *mpq_archive, uint file_number, off_t *offset); -int libmpq__file_blocks(mpq_archive_s *mpq_archive, uint file_number, uint *blocks); -int libmpq__file_encrypted(mpq_archive_s *mpq_archive, uint file_number, uint *encrypted); -int libmpq__file_compressed(mpq_archive_s *mpq_archive, uint file_number, uint *compressed); -int libmpq__file_imploded(mpq_archive_s *mpq_archive, uint file_number, uint *imploded); -int libmpq__file_number(mpq_archive_s *mpq_archive, char *filename, uint *number); -int libmpq__file_read(mpq_archive_s *mpq_archive, uint file_number, ubyte *out_buf, off_t out_size, off_t *transferred); - -/* libmpq__generic block processing functions. */ -int libmpq__block_open_offset(mpq_archive_s *mpq_archive, uint file_number); -int libmpq__block_close_offset(mpq_archive_s *mpq_archive, uint file_number); -int libmpq__block_unpacked_size(mpq_archive_s *mpq_archive, uint file_number, uint block_number, off_t *unpacked_size); -int libmpq__block_read(mpq_archive_s *mpq_archive, uint file_number, uint block_number, ubyte *out_buf, off_t out_size, off_t *transferred); - -} - - -/** exception class for failed libmpq calls */ -class MPQException : Exception { - const string[] Errors = [ - "unknown error", - "open error on file", - "close error on file", - "lseek error on file", - "read error on file", - "write error on file", - "memory allocation error", - "format errror", - "init() wasn't called", - "buffer size is to small", - "file or block does not exist in archive", - "we don't know the decryption seed", - "error on unpacking file"]; - - public int errno; - this(char[] fnname = "unknown_function", int errno = 0) { - - this.errno = errno; - if (-errno >= Errors.length) - errno = 0; - super(std.string.format("Error in %s(): %s (%d)", - fnname, Errors[-errno], errno)); - } -} - - -/** template to wrap function calls and throw exceptions in case of error - * - * thanks for the idea to while(nan) blog, - * http://while-nan.blogspot.com/2007/06/wrapping-functions-for-fun-and-profit.html - * - * use: MPQ_CHECKERR(libmpq__archive_open)(&m, "foo.mpq", -1); - * returns the retval of archive_open on success; - * throws an MPQException on failure. - * - * @param Fn libmpq__function reference - * @param args libmpq__function parameters - * @return return value of libmpq__function on success - * @throw MPQException on error - */ -int MPQ_CHECKERR(alias Fn)(ParameterTypeTuple!(Fn) args) -{ - int result = Fn(args); - if (result < 0) { - /* XXX: relying on non-specified stringof() behaviour */ - throw new MPQException((&Fn).stringof[2..$], result); - } - return result; -} - - -/** mixin alias to wrap library functions into MPQ_CHECKERR. - * - * alias mpq.func_name(...) to MPQ_CHECKERR(libmpq__func_name)(...) - * @param func_name name of the function to be wrapped - */ -template MPQ_FUNC(char[] func_name) { - const char[] MPQ_FUNC = "alias MPQ_CHECKERR!(libmpq__" ~ func_name ~ ") " ~ func_name ~ ";"; -} - -alias libmpq__version libversion; /* must be direct alias because it returns char*, not error int */ -mixin(MPQ_FUNC!("archive_open")); -mixin(MPQ_FUNC!("archive_close")); -mixin(MPQ_FUNC!("archive_packed_size")); -mixin(MPQ_FUNC!("archive_unpacked_size")); -mixin(MPQ_FUNC!("archive_offset")); -mixin(MPQ_FUNC!("archive_version")); -mixin(MPQ_FUNC!("archive_files")); -mixin(MPQ_FUNC!("file_packed_size")); -mixin(MPQ_FUNC!("file_unpacked_size")); -mixin(MPQ_FUNC!("file_offset")); -mixin(MPQ_FUNC!("file_blocks")); -mixin(MPQ_FUNC!("file_encrypted")); -mixin(MPQ_FUNC!("file_compressed")); -mixin(MPQ_FUNC!("file_imploded")); -mixin(MPQ_FUNC!("file_number")); -mixin(MPQ_FUNC!("file_read")); -mixin(MPQ_FUNC!("block_open_offset")); -mixin(MPQ_FUNC!("block_close_offset")); -mixin(MPQ_FUNC!("block_unpacked_size")); -mixin(MPQ_FUNC!("block_read")); - -/** getter function named name for returning archive_* single values: - * - * <type> Archive.<name>() { return libmpq__archive_<name>() } - * - * @param type return type for the original function reference - * @param name name of the original function - * @param name2 name for the prototype (defaults to name, used for "version") - * @return getter function mixin - */ -template MPQ_A_GET(char[] type, char[] name, char[] name2 = name) { - const char[] MPQ_A_GET = type ~ " " ~ name2 ~ "() { " ~ - type ~ " ret; " ~ - "archive_" ~ name ~ "(m, &ret); return ret;" ~ - "}"; -} - -/** wrapper class for an MPQ Archive - * - * syntax: auto a = new mpq.Archive("somefile.mpq"); - */ -class Archive { - mpq_archive_s *m; - File listfile; - char[][] listfiledata; - - this(char[] archivename, off_t offset = -1) { - archive_open(&m, toStringz(archivename), offset); - } - - mixin(MPQ_A_GET!("off_t", "packed_size")); - mixin(MPQ_A_GET!("off_t", "unpacked_size")); - mixin(MPQ_A_GET!("off_t", "offset")); - mixin(MPQ_A_GET!("uint", "version", "version_")); - mixin(MPQ_A_GET!("uint", "files")); - - ~this() { - archive_close(m); - } - - mpq_archive_s* archive() { - return m; - } - - File opIndex(char[] fname) { - return new File(this, fname); - } - File opIndex(int fno) { - return new File(this, fno); - } - - char[][] filelist() { - try { - if (!listfile) { - listfile = this["(listfile)"]; - listfiledata = (cast(char[])listfile.read()).splitlines(); - } - return listfiledata; - } catch (MPQException e) { - return []; - } - } - - /+uint filenumber(char[] filename) { - try { - if (!listfile) { - listfile = this["(listfile)"]; - listfiledata = (cast(char[])listfile.read()).splitlines(); - } - return listfiledata; - } catch (MPQException e) { - return []; - } - }+/ - -} - - -/** getter function named name for returning file_* single values: - * - * <type> File.<name>() { return libmpq__file_<name>() } - * - * @param type return type for the original function reference - * @param name name of the original function - * @param name2 name for the prototype (defaults to name, used for "version") - * @return getter function mixin - */ -template MPQ_F_GET(char[] type, char[] name, char[] name2 = name) { - const char[] MPQ_F_GET = type ~ " " ~ name2 ~ "() { " ~ - type ~ " ret; " ~ - "file_" ~ name ~ "(am, fileno, &ret); " ~ - "return ret;" ~ - "}"; -} - -/** wrapper class for a single file in an MPQ Archive - * - * syntax: - * auto a = new mpq.Archive("somefile.mpq"); - * auto f = a["(listfile)"]; - * auto f2 = a[0]; - * auto f3 = new File(a, "(listfile)"); - */ -class File { - Archive a; - mpq_archive_s* am; - char[] filename; - uint fileno; - - this(Archive a, int fileno) { - this.a = a; - this.am = a.archive(); - if (fileno >= a.files) { - throw new MPQException(format("File(%d)", fileno), - LIBMPQ_ERROR_EXIST); - } - this.filename = format("file%04d.xxx", fileno); - this.fileno = fileno; - } - - this(Archive a, char[] filename) { - this.a = a; - this.am = a.archive(); - this.filename = filename; - /* this line will throw an exception when the file is not there */ - mpq.file_number(am, toStringz(filename), &this.fileno); - } - - mixin(MPQ_F_GET!("off_t", "packed_size")); - mixin(MPQ_F_GET!("off_t", "unpacked_size")); - mixin(MPQ_F_GET!("off_t", "offset")); - mixin(MPQ_F_GET!("uint", "blocks")); - mixin(MPQ_F_GET!("uint", "encrypted")); - mixin(MPQ_F_GET!("uint", "compressed")); - mixin(MPQ_F_GET!("uint", "imploded")); - - uint no() { return fileno; } - char[] name() { return filename; } - - ubyte[] read() { - ubyte[] content; - content.length = this.unpacked_size(); - off_t trans; - mpq.file_read(am, fileno, content.ptr, content.length, &trans); - content.length = trans; - return content; - } -} diff --git a/dep/libmpq/bindings/python/Makefile.am b/dep/libmpq/bindings/python/Makefile.am deleted file mode 100644 index 6971a9b2f6d..00000000000 --- a/dep/libmpq/bindings/python/Makefile.am +++ /dev/null @@ -1,5 +0,0 @@ -# minimum required automake 1.6 -AUTOMAKE_OPTIONS = 1.6 - -# library information and headers which should not be installed. -python_PYTHON = mpq.py diff --git a/dep/libmpq/bindings/python/mpq-info b/dep/libmpq/bindings/python/mpq-info deleted file mode 100644 index 2c67aa1d0cc..00000000000 --- a/dep/libmpq/bindings/python/mpq-info +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python - -from __future__ import division - -import sys - -import mpq - -archive = mpq.Archive(sys.argv[1]) - -print "Name: %s" % sys.argv[1] -print "Version: %s" % archive.filename -print "Offset: %s" % archive.offset -print "Packed size: %s" % archive.packed_size -print "Unpacked size: %s" % archive.unpacked_size -print "Compression ratio: %s" % (archive.packed_size/archive.unpacked_size) diff --git a/dep/libmpq/bindings/python/mpq.py b/dep/libmpq/bindings/python/mpq.py deleted file mode 100644 index cf6ecaae800..00000000000 --- a/dep/libmpq/bindings/python/mpq.py +++ /dev/null @@ -1,322 +0,0 @@ -"""wrapper for libmpq""" - -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -import ctypes -import ctypes.util -import os - -libmpq = ctypes.CDLL(ctypes.util.find_library("mpq")) - -class Error(Exception): - pass - -errors = { - -1: (IOError, "open"), - -2: (IOError, "close"), - -3: (IOError, "seek"), - -4: (IOError, "read"), - -5: (IOError, "write"), - -6: (MemoryError,), - -7: (Error, "file is not an mpq or is corrupted"), - -8: (AssertionError, "not initialized"), - -9: (AssertionError, "buffer size too small"), - -10: (IndexError, "file not in archive"), - -11: (AssertionError, "decrypt"), - -12: (AssertionError, "unpack"), -} - -def check_error(result, func, arguments, errors=errors): - try: - error = errors[result] - except KeyError: - return result - else: - raise error[0](*error[1:]) - -libmpq.libmpq__version.restype = ctypes.c_char_p - -libmpq.libmpq__archive_open.errcheck = check_error -libmpq.libmpq__archive_close.errcheck = check_error -libmpq.libmpq__archive_packed_size.errcheck = check_error -libmpq.libmpq__archive_unpacked_size.errcheck = check_error -libmpq.libmpq__archive_offset.errcheck = check_error -libmpq.libmpq__archive_version.errcheck = check_error -libmpq.libmpq__archive_files.errcheck = check_error - -libmpq.libmpq__file_packed_size.errcheck = check_error -libmpq.libmpq__file_unpacked_size.errcheck = check_error -libmpq.libmpq__file_offset.errcheck = check_error -libmpq.libmpq__file_blocks.errcheck = check_error -libmpq.libmpq__file_encrypted.errcheck = check_error -libmpq.libmpq__file_compressed.errcheck = check_error -libmpq.libmpq__file_imploded.errcheck = check_error -libmpq.libmpq__file_number.errcheck = check_error -libmpq.libmpq__file_read.errcheck = check_error - -libmpq.libmpq__block_open_offset.errcheck = check_error -libmpq.libmpq__block_close_offset.errcheck = check_error -libmpq.libmpq__block_unpacked_size.errcheck = check_error -libmpq.libmpq__block_read.errcheck = check_error - -__version__ = libmpq.libmpq__version() - - -class Reader(object): - def __init__(self, file, libmpq=libmpq): - self._file = file - self._pos = 0 - self._buf = [] - self._cur_block = 0 - libmpq.libmpq__block_open_offset(self._file._archive._mpq, - self._file.number) - - def __iter__(self): - return self - - def __repr__(self): - return "iter(%r)" % self._file - - def seek(self, offset, whence=os.SEEK_SET, os=os): - if whence == os.SEEK_SET: - pass - elif whence == os.SEEK_CUR: - offset += self._pos - elif whence == os.SEEK_END: - offset += self._file.unpacked_size - else: - raise ValueError, "invalid whence" - - if offset >= self._pos: - self.read(offset - self._pos) - else: - self._pos = 0 - self._buf = [] - self._cur_block = 0 - self.read(offset) - - def tell(self): - return self._pos - - def _read_block(self, ctypes=ctypes, libmpq=libmpq): - block_size = ctypes.c_uint64() - libmpq.libmpq__block_unpacked_size(self._file._archive._mpq, - self._file.number, self._cur_block, ctypes.byref(block_size)) - block_data = ctypes.create_string_buffer(block_size.value) - libmpq.libmpq__block_read(self._file._archive._mpq, - self._file.number, self._cur_block, - block_data, ctypes.c_uint64(len(block_data)), None) - self._buf.append(block_data.raw) - self._cur_block += 1 - - def read(self, size=-1): - while size < 0 or sum(map(len, self._buf)) < size: - if self._cur_block == self._file.blocks: - break - self._read_block() - buf = "".join(self._buf) - if size < 0: - ret = buf - self._buf = [] - else: - ret = buf[:size] - self._buf = [buf[size:]] - self._pos += len(ret) - return ret - - def readline(self, os=os): - line = [] - while True: - char = self.read(1) - if char == "": - break - if char not in '\r\n' and line and line[-1] in '\r\n': - self.seek(-1, os.SEEK_CUR) - break - line.append(char) - return ''.join(line) - - def next(self): - line = self.readline() - if not line: - raise StopIteration - return line - - def readlines(self, sizehint=-1): - res = [] - while sizehint < 0 or sum(map(len, res)) < sizehint: - line = self.readline() - if not line: - break - res.append(line) - return res - - xreadlines = __iter__ - - def __del__(self, libmpq=libmpq): - libmpq.libmpq__block_close_offset(self._file._archive._mpq, - self._file.number) - - -class File(object): - def __init__(self, archive, number, ctypes=ctypes, libmpq=libmpq): - self._archive = archive - self.number = number - - for name, atype in [ - ("packed_size", ctypes.c_uint64), - ("unpacked_size", ctypes.c_uint64), - ("offset", ctypes.c_uint64), - ("blocks", ctypes.c_uint32), - ("encrypted", ctypes.c_uint32), - ("compressed", ctypes.c_uint32), - ("imploded", ctypes.c_uint32), - ]: - data = atype() - func = getattr(libmpq, "libmpq__file_"+name) - func(self._archive._mpq, self.number, ctypes.byref(data)) - setattr(self, name, data.value) - - def __str__(self, ctypes=ctypes, libmpq=libmpq): - data = ctypes.create_string_buffer(self.unpacked_size) - libmpq.libmpq__file_read(self._archive._mpq, self.number, - data, ctypes.c_uint64(len(data)), None) - return data.raw - - def __repr__(self): - return "%r[%i]" % (self._archive, self.number) - - def __iter__(self, Reader=Reader): - return Reader(self) - - -class Archive(object): - def __init__(self, source, ctypes=ctypes, File=File, libmpq=libmpq): - self._source = source - if isinstance(source, File): - assert not source.encrypted - assert not source.compressed - assert not source.imploded - self.filename = source._archive.filename - offset = source._archive.offset + source.offset - else: - self.filename = source - offset = -1 - - self._mpq = ctypes.c_void_p() - libmpq.libmpq__archive_open(ctypes.byref(self._mpq), self.filename, - ctypes.c_uint64(offset)) - self._opened = True - - for field_name, field_type in [ - ("packed_size", ctypes.c_uint64), - ("unpacked_size", ctypes.c_uint64), - ("offset", ctypes.c_uint64), - ("version", ctypes.c_uint32), - ("files", ctypes.c_uint32), - ]: - func = getattr(libmpq, "libmpq__archive_" + field_name) - data = field_type() - func(self._mpq, ctypes.byref(data)) - setattr(self, field_name, data.value) - - def __del__(self, libmpq=libmpq): - if getattr(self, "_opened", False): - libmpq.libmpq__archive_close(self._mpq) - - def __len__(self): - return self.files - - def __contains__(self, item, ctypes=ctypes, libmpq=libmpq): - if isinstance(item, str): - data = ctypes.c_uint32() - try: - libmpq.libmpq__file_number(self._mpq, ctypes.c_char_p(item), - ctypes.byref(data)) - except IndexError: - return False - return True - return 0 <= item < self.files - - def __getitem__(self, item, ctypes=ctypes, File=File, libmpq=libmpq): - if isinstance(item, str): - data = ctypes.c_int() - libmpq.libmpq__file_number(self._mpq, ctypes.c_char_p(item), - ctypes.byref(data)) - item = data.value - else: - if not 0 <= item < self.files: - raise IndexError, "file not in archive" - return File(self, item) - - def __repr__(self): - return "mpq.Archive(%r)" % self._source - -# Remove clutter - everything except Error and Archive. -del os, check_error, ctypes, errors, File, libmpq, Reader - -if __name__ == "__main__": - import sys, random - archive = Archive(sys.argv[1]) - print repr(archive) - for k, v in archive.__dict__.iteritems(): - #if k[0] == '_': continue - print " " * (4 - 1), k, v - assert '(listfile)' in archive - assert 0 in archive - assert len(archive) == archive.files - files = [x.strip() for x in archive['(listfile)']] - files.extend(xrange(archive.files)) - for key in files: #sys.argv[2:] if sys.argv[2:] else xrange(archive.files): - file = archive[key] - print - print " " * (4 - 1), repr(file) - for k, v in file.__dict__.iteritems(): - #if k[0] == '_': continue - print " " * (8 - 1), k, v - - a = str(file) - - b = iter(file).read() - - reader = iter(file) - c = [] - while True: - l = random.randrange(1, 10) - d = reader.read(l) - if not d: break - assert len(d) <= l - c.append(d) - c = "".join(c) - - d = [] - reader.seek(0) - for line in reader: - d.append(line) - d = "".join(d) - - assert a == b == c == d, map(hash, [a,b,c,d]) - assert len(a) == file.unpacked_size - - repr(iter(file)) - - - reader.seek(0) - a = reader.readlines() - - reader.seek(0) - b = list(reader) - - assert a == b |
