As usual, CPAN shows the way.
For about a year, I was in a situation with mixed Windows, Unix, AND Mac carriage returns, and I think I can safely say I've seen just about every screw up there is.
I evolved a regex over the years, a "universal line seperator" that handles all three newline formats, and a couple of common ugly mistakes that happen.
About a week ago, I rolled it into a CPAN module.
Go check out
File::LocalizeNewlines.
It's only new, and the recursive mode might not handle binary files cleanly at this point, but all you really need is.
use File::LocalizeNewlines;
File::LocalizeNewlines->localize( $filename );