@@ -511,7 +511,7 @@ void ExternalFileUnit::EndIoStatement() {
511
511
void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord (
512
512
IoErrorHandler &handler) {
513
513
RUNTIME_CHECK (handler, access == Access::Sequential);
514
- std::int32_t header{0 }, footer{0 };
514
+ std::uint32_t header{0 }, footer{0 };
515
515
std::size_t need{recordOffsetInFrame_ + sizeof header};
516
516
std::size_t got{ReadFrame (frameOffsetInFile_, need, handler)};
517
517
// Try to emit informative errors to help debug corrupted files.
@@ -528,17 +528,41 @@ void ExternalFileUnit::BeginSequentialVariableUnformattedInputRecord(
528
528
recordLength = sizeof header + header; // does not include footer
529
529
need = recordOffsetInFrame_ + *recordLength + sizeof footer;
530
530
got = ReadFrame (frameOffsetInFile_, need, handler);
531
- if (got < need) {
531
+ if (got >= need) {
532
+ footer = ReadHeaderOrFooter (recordOffsetInFrame_ + *recordLength);
533
+ }
534
+ if (frameOffsetInFile_ == 0 && recordOffsetInFrame_ == 0 &&
535
+ (got < need || footer != header)) {
536
+ // Maybe an omitted or incorrect byte swap flag setting?
537
+ // Try it the other way, since this is the first record.
538
+ // (N.B. Won't work on files starting with empty records, but there's
539
+ // no good way to know later if all preceding records were empty.)
540
+ swapEndianness_ = !swapEndianness_;
541
+ std::uint32_t header2{ReadHeaderOrFooter (0 )};
542
+ std::size_t recordLength2{sizeof header2 + header2};
543
+ std::size_t need2{recordLength2 + sizeof footer};
544
+ std::size_t got2{ReadFrame (0 , need2, handler)};
545
+ if (got2 >= need2) {
546
+ std::uint32_t footer2{ReadHeaderOrFooter (recordLength2)};
547
+ if (footer2 == header2) {
548
+ error = " Unformatted variable-length sequential file input "
549
+ " failed on the first record, probably due to a need "
550
+ " for byte order data conversion; consider adding "
551
+ " CONVERT='SWAP' to the OPEN statement or adding "
552
+ " FORT_CONVERT=SWAP to the execution environment" ;
553
+ }
554
+ }
555
+ swapEndianness_ = !swapEndianness_;
556
+ }
557
+ if (error) {
558
+ } else if (got < need) {
532
559
error = " Unformatted variable-length sequential file input failed at "
533
560
" record #%jd (file offset %jd): hit EOF reading record with "
534
561
" length %jd bytes" ;
535
- } else {
536
- footer = ReadHeaderOrFooter (recordOffsetInFrame_ + *recordLength);
537
- if (footer != header) {
538
- error = " Unformatted variable-length sequential file input failed at "
539
- " record #%jd (file offset %jd): record header has length %jd "
540
- " that does not match record footer (%jd)" ;
541
- }
562
+ } else if (footer != header) {
563
+ error = " Unformatted variable-length sequential file input failed at "
564
+ " record #%jd (file offset %jd): record header has length %jd "
565
+ " that does not match record footer (%jd)" ;
542
566
}
543
567
}
544
568
if (error) {
@@ -590,7 +614,7 @@ void ExternalFileUnit::BackspaceFixedRecord(IoErrorHandler &handler) {
590
614
591
615
void ExternalFileUnit::BackspaceVariableUnformattedRecord (
592
616
IoErrorHandler &handler) {
593
- std::int32_t header{0 };
617
+ std::uint32_t header{0 };
594
618
auto headerBytes{static_cast <std::int64_t >(sizeof header)};
595
619
frameOffsetInFile_ += recordOffsetInFrame_;
596
620
recordOffsetInFrame_ = 0 ;
@@ -775,8 +799,8 @@ void ExternalFileUnit::PopChildIo(ChildIo &child) {
775
799
child_.reset (child.AcquirePrevious ().release ()); // deletes top child
776
800
}
777
801
778
- std::int32_t ExternalFileUnit::ReadHeaderOrFooter (std::int64_t frameOffset) {
779
- std::int32_t word;
802
+ std::uint32_t ExternalFileUnit::ReadHeaderOrFooter (std::int64_t frameOffset) {
803
+ std::uint32_t word;
780
804
char *wordPtr{reinterpret_cast <char *>(&word)};
781
805
std::memcpy (wordPtr, Frame () + frameOffset, sizeof word);
782
806
if (swapEndianness_) {
0 commit comments