Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot

comment on

( [id://3333] : superdoc . print w/replies, xml ) Need Help??

The way I solved it

Thanks to all those of you who replied to my post. I thought it would be worthwhile to hint at how I solved the issue in case someone has a similar problem later. I mentioned in the post I am using various tools (like XML::SAX) that require file handles of some kind, so any solution has to involve producing IO::Handle like objects.

When reading data this is no problem, I can just read all my file into a scalar, use my encryption algorithm to decrypt then inflate and finally use the reulting vector to create an IO::Handle via IO::Scalar.

When writing data the issue is more complex, I have to pass something that the writing modules can treat as a file handle, but when they are done make sure that the post processing happens. I could have changed my code to add an extra "now save this file" step after every place where files are written, but I decided to create my own IO::Thing to do that work for me.

My first thought was to have an object that held a handle and some extra info, pass all calls through to the handle except close() and when the object is closed do the extra work. That doesn't work because handles are not objects (and life is too short to understand as much about them as I want to).

My second thought was to create a IO::Scalar subclass that can perform a special action when the close it called, that doesn't work either because IO::Scalar implements its objects as a localised GLOB.

My third thought was to badly mangle the definition of IO::Scalar to force the behaviour I wanted. This I did creating my own class called IO::ActionOnClose (the implementation is so horrible I won't troble you with it).

With this class my open function now looks like:

sub _open_file { my($file_name,$mode) = @_; $mode = "r" if(!defined($mode)); my $compress = 1; $compress = "" if($file_name =~ /\.xml$/i); if($mode eq "r") { my $fh = new IO::File($file_name); binmode $fh; my $f1 = ""; while(!$fh->eof()) { my $c = $fh->read($f1,1024*16,length($f1)); } $fh = undef; my $f2 = ""; if(defined($model_passphrase) && $model_passphrase ne "") { # Pad $f1 to the next 8 byte boundary if((length($f1) % 8) != 0) { $f1 .= "\x00" x (8 - (length($f1) % 8)); } my $cipher = new Crypt::Blowfish $model_passphrase; for(my $i=0;(8*$i)<length($f1);$i++) { $f2 .= $cipher->decrypt(substr($f1,8*$i,8)); } $f2 =~ s/\x00+$//s; } else { $f2 = $f1; } # Just in case the file is big save some memory $f1 = ""; my $f3 = ""; if($compress) { $f3 = uncompress($f2); } else { $f3 = $f2; } return new IO::Scalar \$f3; } else { # When writing I want to first get the output, then compress # then encrypt, then write to the file. # So I have to create a handle that does some magic # when it is closed my $buffer; return new IO::ActionOnClose(\$buffer, action => \&_send_file, args => [\$buffer,$file_name,$compress,$model +_passphrase]); } } } sub _send_file { my($f3_ref,$file_name,$compress,$model_passphrase) = @_; # This is the reverse of what _open_file does for # read (even the variable names are the same) my $f2; if($compress) { $f2 = compress(${$f3_ref}); } else { $f2 = ${$f3_ref}; } my $f1 = ""; if(defined($model_passphrase) && $model_passphrase ne "") { my $cipher = new Crypt::Blowfish $model_passphrase; # Pad $f1 to the next 8 byte boundary if((length($f2) % 8) != 0) { $f2 .= "\x00" x (8 - (length($f2) % 8)); } for(my $i=0;8*$i<length($f2);$i++) { $f1 .= $cipher->encrypt(substr($f2,8*$i,8)); } } else { $f1 = $f2; } my $fh = new IO::File($file_name,"w"); binmode $fh; $fh->syswrite($f1,length($f1)); $fh->close(); }

Once again thaks to those who contributed and I hope this helps someone else

In reply to My Solution by hawtin
in thread Compressing and Encrypting files on Windows by hawtin

Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":

  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or How to display code and escape characters are good places to start.