Skip Menu |

This queue is for tickets about the CPU-Emulator-Memory CPAN distribution.

Report information
The Basics
Id: 62379
Status: resolved
Priority: 0/
Queue: CPU-Emulator-Memory

People
Owner: Nobody in particular
Requestors: PSCUST [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.1001
Fixed in: (no value)



Subject: Win32: error reading and writing image files (binmode)
In Win32, binmode() is needed to read and write binary files. The ROM image files read by this module are not correctly represented in the object if they contain LF bytes, because of the Win32 translation of end-of-line characters. The same happens to the RAM image files stored on disk. The attached patch and test file solve this issue: * add binmode() after each open() call * add either 'binmode $fh' or '$fh->binmode' in _readROM() to cope with either filehandles or IO::Handle objects * the test file read_write_binary.pl implements binary read and write functions to be used in the tests; maybe File::Slurp should be used instead * 02-file.t is modified to exercise the bug in Win32, by pokeing a CR and a LF bytes * several test are added to 03-banked-memory-ROM.t to read a problem ROM file (with CR and LF bytes) by file name, by file handle and by IO::File; the dependency to IO::File was also added to Makefile.PL I hope this patch is usefull and can get into the next version of the module. Thank you. Paulo Custodio
Subject: read_write_binary.pl
#!perl use strict; use warnings; use Test::More; sub read_binary { my($file) = @_; local $/ = undef; open(my $fh, $file) || die("Couldn't read $file\n"); binmode($fh); return scalar(<$fh>); } sub write_binary { my($file, $bytes) = @_; open(my $fh, '>', $file) || die("Couldn't create $file\n"); binmode($fh); print $fh $bytes; } # test these functions unlink 'bytes.ram'; write_binary('bytes.ram', "\x01\x0D\x0A"); is(-s 'bytes.ram', 3, "binary file has correct size ..."); $_ = read_binary('bytes.ram'); is($_, "\x01\x0D\x0A", "... and correct content"); ok(unlink('bytes.ram'), "bytes.ram deleted"); 1;
Subject: CPU-Emulator-Memory-1.1001-patch02-RT.txt
diff -cr CPU-Emulator-Memory-1.1001/MANIFEST CPU-Emulator-Memory-1.1001_02/MANIFEST *** CPU-Emulator-Memory-1.1001/MANIFEST 2008-02-28 22:20:36.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/MANIFEST 2010-10-22 17:59:35.551993000 +0100 *************** *** 15,18 **** t/coverage.sh t/pod-coverage.t t/pod.t ! META.yml Module meta-data (added by MakeMaker) --- 15,19 ---- t/coverage.sh t/pod-coverage.t t/pod.t ! t/read_write_binary.pl ! META.yml Module meta-data (added by MakeMaker) diff -cr CPU-Emulator-Memory-1.1001/Makefile.PL CPU-Emulator-Memory-1.1001_02/Makefile.PL *** CPU-Emulator-Memory-1.1001/Makefile.PL 2008-02-28 22:20:05.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/Makefile.PL 2010-10-22 18:00:58.419732800 +0100 *************** *** 5,10 **** --- 5,11 ---- VERSION => 1.1001, PREREQ_PM => { 'Scalar::Util' => 0, + 'IO::File' => 0, 'IO::Scalar' => 0 } ); diff -cr CPU-Emulator-Memory-1.1001/lib/CPU/Emulator/Memory/Banked.pm CPU-Emulator-Memory-1.1001_02/lib/CPU/Emulator/Memory/Banked.pm *** CPU-Emulator-Memory-1.1001/lib/CPU/Emulator/Memory/Banked.pm 2008-02-28 22:15:52.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/lib/CPU/Emulator/Memory/Banked.pm 2010-10-22 18:03:27.158240100 +0100 *************** *** 251,256 **** --- 251,262 ---- if(reftype($file) eq 'GLOB') { local $/ = undef; + if (eval {$file->can('binmode')}) { + $file->binmode; # IO::HANDLE + } + else { + binmode $file; # file handle + } my $contents = <$file>; die("data in filehandle is wrong size (got ".length($contents).", expected $size)\n") unless(length($contents) == $size); return $contents; diff -cr CPU-Emulator-Memory-1.1001/lib/CPU/Emulator/Memory.pm CPU-Emulator-Memory-1.1001_02/lib/CPU/Emulator/Memory.pm *** CPU-Emulator-Memory-1.1001/lib/CPU/Emulator/Memory.pm 2008-02-28 19:41:29.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/lib/CPU/Emulator/Memory.pm 2010-10-22 18:04:12.964860100 +0100 *************** *** 172,177 **** --- 172,178 ---- my($self, $file, $size) = @_; local $/ = undef; open(my $fh, $file) || die("Couldn't read $file\n"); + binmode($fh); my $contents = <$fh>; die("$file is wrong size\n") unless(length($contents) == $size); close($fh); *************** *** 192,197 **** --- 193,199 ---- sub _writeRAM { my($self, $file, $contents) = @_; open(my $fh, '>', $file) || die("Can't write $file\n"); + binmode($fh); print $fh $contents || die("Can't write $file\n"); close($fh); } diff -cr CPU-Emulator-Memory-1.1001/t/02-file.t CPU-Emulator-Memory-1.1001_02/t/02-file.t *** CPU-Emulator-Memory-1.1001/t/02-file.t 2008-02-14 13:29:03.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/t/02-file.t 2010-10-22 16:32:10.243978500 +0100 *************** *** 1,25 **** use strict; $^W = 1; ! use Test::More tests => 5; use CPU::Emulator::Memory; unlink 'newfile.ram'; my $memory = CPU::Emulator::Memory->new(file => 'newfile.ram'); # NB using {0xHEXSTUFF} in regexes doesn't work. # and the repeated {30000}...{30000} is cos there's a 2^15 - 2 limit ! $/ = undef; ! open(my $fh, 'newfile.ram') || die("Couldn't open newfile.ram\n"); ! ok(<$fh> =~ /^\000{30000}\000{30000}\000{5536}$/, "New file created as all zeroes"); ! close($fh); ok($memory->peek(0) == 0, "Peek confirms a zero"); ! ok($memory->poke(0, 1) && $memory->peek(0) == 1, "Poke works ..."); ! open($fh, 'newfile.ram'); ! ok(<$fh> =~ /^\001\000{30000}\000{30000}\000{5535}$/, "... and is reflected in the file"); ! close($fh); undef $memory; --- 1,28 ---- use strict; $^W = 1; ! use Test::More tests => 11; use CPU::Emulator::Memory; + require 't/read_write_binary.pl'; + unlink 'newfile.ram'; my $memory = CPU::Emulator::Memory->new(file => 'newfile.ram'); # NB using {0xHEXSTUFF} in regexes doesn't work. # and the repeated {30000}...{30000} is cos there's a 2^15 - 2 limit ! $_ = read_binary('newfile.ram'); ! ok(/^\000{30000}\000{30000}\000{5536}$/, "New file created as all zeroes"); ! ok($memory->peek(0) == 0, "Peek confirms a zero"); ! ok($memory->poke(0, 1) && $memory->peek(0) == 1, "Poke works ..."); ! ok($memory->poke(1, 13) && $memory->peek(1) == 13, "Poke works ..."); ! ok($memory->poke(2, 10) && $memory->peek(2) == 10, "Poke works ..."); ! is(-s 'newfile.ram', 0x10000, "file is correct size"); ! $_ = read_binary('newfile.ram'); ! ok(/^\001\015\012\000{30000}\000{30000}\000{5533}$/s, "... and is reflected in the file"); undef $memory; diff -cr CPU-Emulator-Memory-1.1001/t/03-banked-memory-ROM.t CPU-Emulator-Memory-1.1001_02/t/03-banked-memory-ROM.t *** CPU-Emulator-Memory-1.1001/t/03-banked-memory-ROM.t 2008-02-28 19:41:29.000000000 +0000 --- CPU-Emulator-Memory-1.1001_02/t/03-banked-memory-ROM.t 2010-10-22 17:21:28.852201300 +0100 *************** *** 1,12 **** use strict; $^W = 1; ! use Test::More tests => 19; ! ! undef $/; use CPU::Emulator::Memory::Banked; use IO::Scalar; unlink 'ramfile.ram', 'romfile.rom'; my $memory = CPU::Emulator::Memory::Banked->new(file => 'ramfile.ram'); --- 1,13 ---- use strict; $^W = 1; ! use Test::More tests => 33; use CPU::Emulator::Memory::Banked; use IO::Scalar; + use IO::File; + + require 't/read_write_binary.pl'; unlink 'ramfile.ram', 'romfile.rom'; my $memory = CPU::Emulator::Memory::Banked->new(file => 'ramfile.ram'); *************** *** 14,22 **** # NB using {0xHEXSTUFF} in regexes doesn't work. # and the repeated {30000}...{30000} is cos there's a 2^15 - 2 limit ! open(my $fh, '>', 'romfile.rom') || die("Can't create ROM file for testing\n"); ! print $fh 'This is a ROM'; ! close($fh); eval { $memory->bank( address => 0, --- 15,21 ---- # NB using {0xHEXSTUFF} in regexes doesn't work. # and the repeated {30000}...{30000} is cos there's a 2^15 - 2 limit ! write_binary('romfile.rom', 'This is a ROM'); eval { $memory->bank( address => 0, *************** *** 54,64 **** ok($memory->peek(1) == 1, "With writethrough, RAM gets updated"); ok($memory->peek(2) == 1, "poke8 worked too"); ! open($fh, 'romfile.rom') || die("Can't read romfile.rom\n"); ! ok(<$fh> eq 'This is a ROM', "ROM files don't get altered"); ! close($fh); ! open($fh, 'ramfile.ram') || die("Can't read ramfile.ram\n"); ! ok(<$fh> =~ /^\000\001{2}\000{30000}\000{30000}\000{5532}\001$/, "With writethrough, RAM file gets updated correctly"); $memory->bank( address => 0, --- 53,63 ---- ok($memory->peek(1) == 1, "With writethrough, RAM gets updated"); ok($memory->peek(2) == 1, "poke8 worked too"); ! $_ = read_binary('romfile.rom'); ! ok($_ eq 'This is a ROM', "ROM files don't get altered"); ! ! $_ = read_binary('ramfile.ram'); ! ok(/^\000\001{2}\000{30000}\000{30000}\000{5532}\001$/, "With writethrough, RAM file gets updated correctly"); $memory->bank( address => 0, *************** *** 104,108 **** --- 103,148 ---- ); ok($memory->peek(0) == ord('A'), "ROM 'file' can also be a filehandle"); + # test banked ROM with chr(13) and chr(10) inside + # - needs binmode to read/write correctly in Win32 + write_binary('romfile.rom', "\x01\x0D\x0A"); + is(-s 'romfile.rom', 3, "binmode was used, size is OK"); + $memory->bank( + address => 0, + size => 3, + type => 'ROM', + file => 'romfile.rom' + ); + is($memory->peek(0), 1, "peek 1"); + is($memory->peek(1), 13, "peek 13"); + is($memory->peek(2), 10, "peek 10"); + + # test with filehandle + open(my $fh, 'romfile.rom') || die("Couldn't read romfile.rom\n"); + $memory->bank( + address => 0, + size => 3, + type => 'ROM', + file => $fh + ); + is($memory->peek(0), 1, "peek 1"); + is($memory->peek(1), 13, "peek 13"); + is($memory->peek(2), 10, "peek 10"); + close $fh; + + # test with IO::File + $memory->bank( + address => 0, + size => 3, + type => 'ROM', + file => IO::File->new('romfile.rom', 'r') + ); + is($memory->peek(0), 1, "peek 1"); + is($memory->peek(1), 13, "peek 13"); + is($memory->peek(2), 10, "peek 10"); + + undef $memory; # to release IO::File handle + ok(unlink('romfile.rom'), "romfile.rom deleted"); + __DATA__ A Only in CPU-Emulator-Memory-1.1001_02/t: read_write_binary.pl
Thanks, will be fixed in next release