Index: GenericIO.cxx
===================================================================
--- GenericIO.cxx	(revision da65757e00f1d262bf6da9c45b4a33e8b80b8e88)
+++ GenericIO.cxx	(revision a4fee139105de3bf748818b08fe85b87b6d2bf56)
@@ -238,4 +238,47 @@
 }
 
+static void bswap(void *v, size_t s) {
+  char *p = (char *) v;
+  for (size_t i = 0; i < s/2; ++i)
+    std::swap(p[i], p[s - (i+1)]);
+}
+
+// Using #pragma pack here, instead of __attribute__((packed)) because xlc, at
+// least as of v12.1, won't take __attribute__((packed)) on non-POD and/or
+// templated types.
+#pragma pack(1)
+
+template <typename T, bool IsBigEndian>
+struct endian_specific_value {
+  operator T() const {
+    T rvalue = value;
+    if (IsBigEndian != isBigEndian())
+      bswap(&rvalue, sizeof(T));
+
+    return rvalue;
+  };
+
+  endian_specific_value &operator = (T nvalue) {
+    if (IsBigEndian != isBigEndian())
+      bswap(&nvalue, sizeof(T));
+
+    value = nvalue;
+    return *this;
+  }
+
+  endian_specific_value &operator += (T nvalue) {
+    *this = *this + nvalue;
+    return *this;
+  }
+
+  endian_specific_value &operator -= (T nvalue) {
+    *this = *this - nvalue;
+    return *this;
+  }
+
+private:
+  T value;
+};
+
 static const size_t CRCSize = 8;
 
@@ -244,21 +287,22 @@
 static const char *MagicLE = "HACC01L";
 
+template <bool IsBigEndian>
 struct GlobalHeader {
   char Magic[MagicSize];
-  uint64_t HeaderSize;
-  uint64_t NElems; // The global total
-  uint64_t Dims[3];
-  uint64_t NVars;
-  uint64_t VarsSize;
-  uint64_t VarsStart;
-  uint64_t NRanks;
-  uint64_t RanksSize;
-  uint64_t RanksStart;
-  uint64_t GlobalHeaderSize;
-  double   PhysOrigin[3];
-  double   PhysScale[3];
-  uint64_t BlocksSize;
-  uint64_t BlocksStart;
-} __attribute__((packed));
+  endian_specific_value<uint64_t, IsBigEndian> HeaderSize;
+  endian_specific_value<uint64_t, IsBigEndian> NElems; // The global total
+  endian_specific_value<uint64_t, IsBigEndian> Dims[3];
+  endian_specific_value<uint64_t, IsBigEndian> NVars;
+  endian_specific_value<uint64_t, IsBigEndian> VarsSize;
+  endian_specific_value<uint64_t, IsBigEndian> VarsStart;
+  endian_specific_value<uint64_t, IsBigEndian> NRanks;
+  endian_specific_value<uint64_t, IsBigEndian> RanksSize;
+  endian_specific_value<uint64_t, IsBigEndian> RanksStart;
+  endian_specific_value<uint64_t, IsBigEndian> GlobalHeaderSize;
+  endian_specific_value<double,   IsBigEndian> PhysOrigin[3];
+  endian_specific_value<double,   IsBigEndian> PhysScale[3];
+  endian_specific_value<uint64_t, IsBigEndian> BlocksSize;
+  endian_specific_value<uint64_t, IsBigEndian> BlocksStart;
+};
 
 enum {
@@ -272,29 +316,35 @@
 
 static const size_t NameSize = 256;
+template <bool IsBigEndian>
 struct VariableHeader {
   char Name[NameSize];
-  uint64_t Flags;
-  uint64_t Size;
-} __attribute__((packed));
-
+  endian_specific_value<uint64_t, IsBigEndian> Flags;
+  endian_specific_value<uint64_t, IsBigEndian> Size;
+};
+
+template <bool IsBigEndian>
 struct RankHeader {
-  uint64_t Coords[3];
-  uint64_t NElems;
-  uint64_t Start;
-  uint64_t GlobalRank;
-} __attribute__((packed));
+  endian_specific_value<uint64_t, IsBigEndian> Coords[3];
+  endian_specific_value<uint64_t, IsBigEndian> NElems;
+  endian_specific_value<uint64_t, IsBigEndian> Start;
+  endian_specific_value<uint64_t, IsBigEndian> GlobalRank;
+};
 
 static const size_t FilterNameSize = 8;
 static const size_t MaxFilters = 4;
+template <bool IsBigEndian>
 struct BlockHeader {
   char Filters[MaxFilters][FilterNameSize];
-  uint64_t Start;
-  uint64_t Size;
-} __attribute__((packed));
-
+  endian_specific_value<uint64_t, IsBigEndian> Start;
+  endian_specific_value<uint64_t, IsBigEndian> Size;
+};
+
+template <bool IsBigEndian>
 struct CompressHeader {
-  uint64_t OrigCRC;
-} __attribute__((packed));
+  endian_specific_value<uint64_t, IsBigEndian> OrigCRC;
+};
 const char *CompressName = "BLOSC";
+
+#pragma pack()
 
 unsigned GenericIO::DefaultFileIOType = FileIOPOSIX;
@@ -309,8 +359,16 @@
 
 #ifndef GENERICIO_NO_MPI
+void GenericIO::write() {
+  if (isBigEndian())
+    write<true>();
+  else
+    write<false>();
+}
+
 // Note: writing errors are not currently recoverable (one rank may fail
 // while the others don't).
+template <bool IsBigEndian>
 void GenericIO::write() {
-  const char *Magic = isBigEndian() ? MagicBE : MagicLE;
+  const char *Magic = IsBigEndian ? MagicBE : MagicLE;
 
   uint64_t FileSize = 0;
@@ -383,5 +441,5 @@
   }
 
-  RankHeader RHLocal;
+  RankHeader<IsBigEndian> RHLocal;
   int Dims[3], Periods[3], Coords[3];
 
@@ -417,5 +475,5 @@
   }
 
-  vector<BlockHeader> LocalBlockHeaders;
+  vector<BlockHeader<IsBigEndian> > LocalBlockHeaders;
   vector<void *> LocalData;
   vector<bool> LocalHasExtraSpace;
@@ -431,9 +489,9 @@
       // Filters null by default, leave null starting address (needs to be
       // calculated by the header-writing rank).
-      memset(&LocalBlockHeaders[i], 0, sizeof(BlockHeader));
+      memset(&LocalBlockHeaders[i], 0, sizeof(BlockHeader<IsBigEndian>));
       if (ShouldCompress) {
-        LocalCData[i].resize(sizeof(CompressHeader));
-
-        CompressHeader *CH = (CompressHeader*) &LocalCData[i][0];
+        LocalCData[i].resize(sizeof(CompressHeader<IsBigEndian>));
+
+        CompressHeader<IsBigEndian> *CH = (CompressHeader<IsBigEndian>*) &LocalCData[i][0];
         CH->OrigCRC = crc64_omp(Vars[i].Data, Vars[i].Size*NElems);
 
@@ -455,5 +513,5 @@
         LocalCData[i].resize(LocalCData[i].size() + NElems*Vars[i].Size);
         if (blosc_compress(9, 1, Vars[i].Size, NElems*Vars[i].Size, Vars[i].Data,
-                           &LocalCData[i][0] + sizeof(CompressHeader),
+                           &LocalCData[i][0] + sizeof(CompressHeader<IsBigEndian>),
                            NElems*Vars[i].Size) <= 0)
           goto nocomp;
@@ -461,7 +519,7 @@
         strncpy(LocalBlockHeaders[i].Filters[0], CompressName, FilterNameSize);
         size_t CNBytes, CCBytes, CBlockSize;
-        blosc_cbuffer_sizes(&LocalCData[i][0] + sizeof(CompressHeader),
+        blosc_cbuffer_sizes(&LocalCData[i][0] + sizeof(CompressHeader<IsBigEndian>),
                             &CNBytes, &CCBytes, &CBlockSize);
-        LocalCData[i].resize(CCBytes + sizeof(CompressHeader));
+        LocalCData[i].resize(CCBytes + sizeof(CompressHeader<IsBigEndian>));
 
         LocalBlockHeaders[i].Size = LocalCData[i].size();
@@ -481,11 +539,11 @@
 
   if (SplitRank == 0) {
-    uint64_t HeaderSize = sizeof(GlobalHeader) + Vars.size()*sizeof(VariableHeader) +
-                          SplitNRanks*sizeof(RankHeader) + CRCSize;
+    uint64_t HeaderSize = sizeof(GlobalHeader<IsBigEndian>) + Vars.size()*sizeof(VariableHeader<IsBigEndian>) +
+                          SplitNRanks*sizeof(RankHeader<IsBigEndian>) + CRCSize;
     if (NeedsBlockHeaders)
-      HeaderSize += SplitNRanks*Vars.size()*sizeof(BlockHeader);
+      HeaderSize += SplitNRanks*Vars.size()*sizeof(BlockHeader<IsBigEndian>);
 
     vector<char> Header(HeaderSize, 0);
-    GlobalHeader *GH = (GlobalHeader *) &Header[0];
+    GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &Header[0];
     std::copy(Magic, Magic + MagicSize, GH->Magic);
     GH->HeaderSize = HeaderSize - CRCSize;
@@ -493,10 +551,10 @@
     std::copy(Dims, Dims + 3, GH->Dims);
     GH->NVars = Vars.size();
-    GH->VarsSize = sizeof(VariableHeader);
-    GH->VarsStart = sizeof(GlobalHeader);
+    GH->VarsSize = sizeof(VariableHeader<IsBigEndian>);
+    GH->VarsStart = sizeof(GlobalHeader<IsBigEndian>);
     GH->NRanks = SplitNRanks;
-    GH->RanksSize = sizeof(RankHeader);
-    GH->RanksStart = GH->VarsStart + Vars.size()*sizeof(VariableHeader);
-    GH->GlobalHeaderSize = sizeof(GlobalHeader);
+    GH->RanksSize = sizeof(RankHeader<IsBigEndian>);
+    GH->RanksStart = GH->VarsStart + Vars.size()*sizeof(VariableHeader<IsBigEndian>);
+    GH->GlobalHeaderSize = sizeof(GlobalHeader<IsBigEndian>);
     std::copy(PhysOrigin, PhysOrigin + 3, GH->PhysOrigin);
     std::copy(PhysScale,  PhysScale  + 3, GH->PhysScale);
@@ -504,10 +562,10 @@
       GH->BlocksSize = GH->BlocksStart = 0;
     } else {
-      GH->BlocksSize = sizeof(BlockHeader);
-      GH->BlocksStart = GH->RanksStart + SplitNRanks*sizeof(RankHeader);
+      GH->BlocksSize = sizeof(BlockHeader<IsBigEndian>);
+      GH->BlocksStart = GH->RanksStart + SplitNRanks*sizeof(RankHeader<IsBigEndian>);
     }
 
     uint64_t RecordSize = 0;
-    VariableHeader *VH = (VariableHeader *) &Header[GH->VarsStart];
+    VariableHeader<IsBigEndian> *VH = (VariableHeader<IsBigEndian> *) &Header[GH->VarsStart];
     for (size_t i = 0; i < Vars.size(); ++i, ++VH) {
       string VName(Vars[i].Name);
@@ -515,10 +573,12 @@
 
       std::copy(VName.begin(), VName.end(), VH->Name);
-      if (Vars[i].IsFloat)  VH->Flags |= FloatValue;
-      if (Vars[i].IsSigned) VH->Flags |= SignedValue;
-      if (Vars[i].IsPhysCoordX) VH->Flags |= ValueIsPhysCoordX;
-      if (Vars[i].IsPhysCoordY) VH->Flags |= ValueIsPhysCoordY;
-      if (Vars[i].IsPhysCoordZ) VH->Flags |= ValueIsPhysCoordZ;
-      if (Vars[i].MaybePhysGhost) VH->Flags |= ValueMaybePhysGhost;
+      uint64_t VFlags = 0;
+      if (Vars[i].IsFloat)  VFlags |= FloatValue;
+      if (Vars[i].IsSigned) VFlags |= SignedValue;
+      if (Vars[i].IsPhysCoordX) VFlags |= ValueIsPhysCoordX;
+      if (Vars[i].IsPhysCoordY) VFlags |= ValueIsPhysCoordY;
+      if (Vars[i].IsPhysCoordZ) VFlags |= ValueIsPhysCoordZ;
+      if (Vars[i].MaybePhysGhost) VFlags |= ValueMaybePhysGhost;
+      VH->Flags = VFlags;
       RecordSize += VH->Size = Vars[i].Size;
     }
@@ -530,10 +590,10 @@
     if (NeedsBlockHeaders) {
       MPI_Gather(&LocalBlockHeaders[0],
-                 Vars.size()*sizeof(BlockHeader), MPI_BYTE,
+                 Vars.size()*sizeof(BlockHeader<IsBigEndian>), MPI_BYTE,
                  &Header[GH->BlocksStart],
-                 Vars.size()*sizeof(BlockHeader), MPI_BYTE,
+                 Vars.size()*sizeof(BlockHeader<IsBigEndian>), MPI_BYTE,
                  0, SplitComm);
 
-      BlockHeader *BH = (BlockHeader *) &Header[GH->BlocksStart];
+      BlockHeader<IsBigEndian> *BH = (BlockHeader<IsBigEndian> *) &Header[GH->BlocksStart];
       for (int i = 0; i < SplitNRanks; ++i)
       for (size_t j = 0; j < Vars.size(); ++j, ++BH) {
@@ -544,9 +604,9 @@
       }
 
-      RankHeader *RH = (RankHeader *) &Header[GH->RanksStart];
+      RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &Header[GH->RanksStart];
       RH->Start = HeaderSize; ++RH;
       for (int i = 1; i < SplitNRanks; ++i, ++RH) {
         RH->Start =
-          ((BlockHeader *) &Header[GH->BlocksStart])[i*Vars.size()].Start;
+          ((BlockHeader<IsBigEndian> *) &Header[GH->BlocksStart])[i*Vars.size()].Start;
         GH->NElems += RH->NElems;
       }
@@ -556,5 +616,5 @@
       FileSize = BH[-1].Start + LastData;
     } else {
-      RankHeader *RH = (RankHeader *) &Header[GH->RanksStart];
+      RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &Header[GH->RanksStart];
       RH->Start = HeaderSize; ++RH;
       for (int i = 1; i < SplitNRanks; ++i, ++RH) {
@@ -578,7 +638,7 @@
     if (NeedsBlockHeaders)
       MPI_Scatter(&Header[GH->BlocksStart],
-                  sizeof(BlockHeader)*Vars.size(), MPI_BYTE,
+                  sizeof(BlockHeader<IsBigEndian>)*Vars.size(), MPI_BYTE,
                   &LocalBlockHeaders[0],
-                  sizeof(BlockHeader)*Vars.size(), MPI_BYTE,
+                  sizeof(BlockHeader<IsBigEndian>)*Vars.size(), MPI_BYTE,
                   0, SplitComm);
 
@@ -601,9 +661,9 @@
     MPI_Gather(&RHLocal, sizeof(RHLocal), MPI_BYTE, 0, 0, MPI_BYTE, 0, SplitComm);
     if (NeedsBlockHeaders)
-      MPI_Gather(&LocalBlockHeaders[0], Vars.size()*sizeof(BlockHeader),
+      MPI_Gather(&LocalBlockHeaders[0], Vars.size()*sizeof(BlockHeader<IsBigEndian>),
                  MPI_BYTE, 0, 0, MPI_BYTE, 0, SplitComm);
     MPI_Scatter(0, 0, MPI_BYTE, &RHLocal, sizeof(RHLocal), MPI_BYTE, 0, SplitComm);
     if (NeedsBlockHeaders)
-      MPI_Scatter(0, 0, MPI_BYTE, &LocalBlockHeaders[0], sizeof(BlockHeader)*Vars.size(),
+      MPI_Scatter(0, 0, MPI_BYTE, &LocalBlockHeaders[0], sizeof(BlockHeader<IsBigEndian>)*Vars.size(),
                   MPI_BYTE, 0, SplitComm);
   }
@@ -678,10 +738,58 @@
 #endif // GENERICIO_NO_MPI
 
+template <bool IsBigEndian>
+void GenericIO::readHeaderLeader(void *GHPtr, bool MustMatch, int SplitNRanks,
+                                 string &LocalFileName, uint64_t &HeaderSize, vector<char> &Header) {
+  GlobalHeader<IsBigEndian> &GH = *(GlobalHeader<IsBigEndian> *) GHPtr;
+
+  if (MustMatch) {
+    if (SplitNRanks != (int) GH.NRanks) {
+      stringstream ss;
+      ss << "Won't read " << LocalFileName << ": communicator-size mismatch: " <<
+            "current: " << SplitNRanks << ", file: " << GH.NRanks;
+      throw runtime_error(ss.str());
+    }
+
+#ifndef GENERICIO_NO_MPI
+    int TopoStatus;
+    MPI_Topo_test(Comm, &TopoStatus);
+    if (TopoStatus == MPI_CART) {
+      int Dims[3], Periods[3], Coords[3];
+      MPI_Cart_get(Comm, 3, Dims, Periods, Coords);
+
+      bool DimsMatch = true;
+      for (int i = 0; i < 3; ++i) {
+        if ((uint64_t) Dims[i] != GH.Dims[i]) {
+          DimsMatch = false;
+          break;
+        }
+      }
+
+      if (!DimsMatch) {
+        stringstream ss;
+        ss << "Won't read " << LocalFileName <<
+              ": communicator-decomposition mismatch: " <<
+              "current: " << Dims[0] << "x" << Dims[1] << "x" << Dims[2] <<
+              ", file: " << GH.Dims[0] << "x" << GH.Dims[1] << "x" <<
+              GH.Dims[2];
+        throw runtime_error(ss.str());
+      }
+    }
+#endif
+  }
+
+  HeaderSize = GH.HeaderSize;
+  Header.resize(HeaderSize + CRCSize, 0xFE /* poison */);
+  FH.get()->read(&Header[0], HeaderSize + CRCSize, 0, "header");
+
+  uint64_t CRC = crc64_omp(&Header[0], HeaderSize + CRCSize);
+  if (CRC != (uint64_t) -1) {
+    throw runtime_error("Header CRC check failed: " + LocalFileName);
+  }
+}
+
 // Note: Errors from this function should be recoverable. This means that if
 // one rank throws an exception, then all ranks should.
 void GenericIO::openAndReadHeader(bool MustMatch, int EffRank, bool CheckPartMap) {
-  const char *Magic = isBigEndian() ? MagicBE : MagicLE;
-  const char *MagicInv = isBigEndian() ? MagicLE : MagicBE;
-
   int NRanks, Rank;
 #ifndef GENERICIO_NO_MPI
@@ -785,60 +893,16 @@
       FH.get()->open(LocalFileName, true);
 
-      GlobalHeader GH;
-      FH.get()->read(&GH, sizeof(GlobalHeader), 0, "global header");
-
-      if (string(GH.Magic, GH.Magic + MagicSize - 1) != Magic) {
-        string Error;
-        if (string(GH.Magic, GH.Magic + MagicSize - 1) == MagicInv) {
-          Error = "wrong endianness";
-        } else {
-          Error = "invalid file-type identifier";
-        }
+      GlobalHeader<false> GH; // endianness does not matter yet...
+      FH.get()->read(&GH, sizeof(GlobalHeader<false>), 0, "global header");
+
+      if (string(GH.Magic, GH.Magic + MagicSize - 1) == MagicLE) {
+        readHeaderLeader<false>(&GH, MustMatch, SplitNRanks, LocalFileName,
+                                HeaderSize, Header);
+      } else if (string(GH.Magic, GH.Magic + MagicSize - 1) == MagicBE) {
+        readHeaderLeader<true>(&GH, MustMatch, SplitNRanks, LocalFileName,
+                               HeaderSize, Header);
+      } else {
+        string Error = "invalid file-type identifier";
         throw runtime_error("Won't read " + LocalFileName + ": " + Error);
-      }
-
-      if (MustMatch) {
-        if (SplitNRanks != (int) GH.NRanks) {
-          stringstream ss;
-          ss << "Won't read " << LocalFileName << ": communicator-size mismatch: " <<
-                "current: " << SplitNRanks << ", file: " << GH.NRanks;
-          throw runtime_error(ss.str());
-        }
-
-#ifndef GENERICIO_NO_MPI
-        int TopoStatus;
-        MPI_Topo_test(Comm, &TopoStatus);
-        if (TopoStatus == MPI_CART) {
-          int Dims[3], Periods[3], Coords[3];
-          MPI_Cart_get(Comm, 3, Dims, Periods, Coords);
-
-          bool DimsMatch = true;
-          for (int i = 0; i < 3; ++i) {
-            if ((uint64_t) Dims[i] != GH.Dims[i]) {
-              DimsMatch = false;
-              break;
-            }
-          }
-
-          if (!DimsMatch) {
-            stringstream ss;
-            ss << "Won't read " << LocalFileName <<
-                  ": communicator-decomposition mismatch: " <<
-                  "current: " << Dims[0] << "x" << Dims[1] << "x" << Dims[2] <<
-                  ", file: " << GH.Dims[0] << "x" << GH.Dims[1] << "x" <<
-                  GH.Dims[2];
-            throw runtime_error(ss.str());
-          }
-        }
-#endif
-      }
-
-      HeaderSize = GH.HeaderSize;
-      Header.resize(HeaderSize + CRCSize, 0xFE /* poison */);
-      FH.get()->read(&Header[0], HeaderSize + CRCSize, 0, "header");
-
-      uint64_t CRC = crc64_omp(&Header[0], HeaderSize + CRCSize);
-      if (CRC != (uint64_t) -1) {
-        throw runtime_error("Header CRC check failed: " + LocalFileName);
       }
 
@@ -872,5 +936,10 @@
 #endif
 
+
   FH.getHeaderCache().clear();
+
+  GlobalHeader<false> *GH = (GlobalHeader<false> *) &Header[0];
+  FH.setIsBigEndian(string(GH->Magic, GH->Magic + MagicSize - 1) == MagicBE);
+
   FH.getHeaderCache().swap(Header);
   OpenFileName = LocalFileName;
@@ -905,18 +974,40 @@
 
 int GenericIO::readNRanks() {
+  if (FH.isBigEndian())
+    return readNRanks<true>();
+  return readNRanks<false>();
+}
+
+template <bool IsBigEndian>
+int GenericIO::readNRanks() {
   if (RankMap.size())
     return RankMap.size();
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
   return (int) GH->NRanks;
 }
 
+void GenericIO::readDims(int Dims[3]) {
+  if (FH.isBigEndian())
+    readDims<true>(Dims);
+  else
+    readDims<false>(Dims);
+}
+
+template <bool IsBigEndian>
 void GenericIO::readDims(int Dims[3]) {
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
   std::copy(GH->Dims, GH->Dims + 3, Dims);
 }
 
+uint64_t GenericIO::readTotalNumElems() {
+  if (FH.isBigEndian())
+    return readTotalNumElems<true>();
+  return readTotalNumElems<false>();
+}
+
+template <bool IsBigEndian>
 uint64_t GenericIO::readTotalNumElems() {
   if (RankMap.size())
@@ -924,12 +1015,24 @@
 
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
   return GH->NElems;
 }
 
+void GenericIO::readPhysOrigin(double Origin[3]) {
+  if (FH.isBigEndian())
+    readPhysOrigin<true>(Origin);
+  else
+    readPhysOrigin<false>(Origin);
+}
+
+// Define a "safe" version of offsetof (offsetof itself might not work for
+// non-POD types, and at least xlC v12.1 will complain about this if you try).
+#define offsetof_safe(S, F) (size_t(&(S)->F) - size_t(S))
+
+template <bool IsBigEndian>
 void GenericIO::readPhysOrigin(double Origin[3]) {
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  if (offsetof(GlobalHeader, PhysOrigin) >= GH->GlobalHeaderSize) {
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  if (offsetof_safe(GH, PhysOrigin) >= GH->GlobalHeaderSize) {
     std::fill(Origin, Origin + 3, 0.0);
     return;
@@ -940,7 +1043,15 @@
 
 void GenericIO::readPhysScale(double Scale[3]) {
+  if (FH.isBigEndian())
+    readPhysScale<true>(Scale);
+  else
+    readPhysScale<false>(Scale);
+}
+
+template <bool IsBigEndian>
+void GenericIO::readPhysScale(double Scale[3]) {
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  if (offsetof(GlobalHeader, PhysScale) >= GH->GlobalHeaderSize) {
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  if (offsetof_safe(GH, PhysScale) >= GH->GlobalHeaderSize) {
     std::fill(Scale, Scale + 3, 0.0);
     return;
@@ -950,12 +1061,16 @@
 }
 
-static size_t getRankIndex(int EffRank, GlobalHeader *GH,
+template <bool IsBigEndian>
+static size_t getRankIndex(int EffRank, GlobalHeader<IsBigEndian> *GH,
                            vector<int> &RankMap, vector<char> &HeaderCache) {
-  if (offsetof(RankHeader, GlobalRank) >= GH->RanksSize || RankMap.empty())
+  if (RankMap.empty())
     return EffRank;
 
   for (size_t i = 0; i < GH->NRanks; ++i) {
-    RankHeader *RH = (RankHeader *) &HeaderCache[GH->RanksStart +
+    RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &HeaderCache[GH->RanksStart +
                                                  i*GH->RanksSize];
+    if (offsetof_safe(RH, GlobalRank) >= GH->RanksSize)
+      return EffRank;
+
     if ((int) RH->GlobalRank == EffRank)
       return i;
@@ -966,4 +1081,11 @@
 }
 
+int GenericIO::readGlobalRankNumber(int EffRank) {
+  if (FH.isBigEndian())
+    return readGlobalRankNumber<true>(EffRank);
+  return readGlobalRankNumber<false>(EffRank);
+}
+
+template <bool IsBigEndian>
 int GenericIO::readGlobalRankNumber(int EffRank) {
   if (EffRank == -1) {
@@ -979,18 +1101,25 @@
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
 
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  size_t RankIndex = getRankIndex(EffRank, GH, RankMap, FH.getHeaderCache());
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  size_t RankIndex = getRankIndex<IsBigEndian>(EffRank, GH, RankMap, FH.getHeaderCache());
 
   assert(RankIndex < GH->NRanks && "Invalid rank specified");
 
-  if (offsetof(RankHeader, GlobalRank) >= GH->RanksSize)
+  RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->RanksStart +
+                                               RankIndex*GH->RanksSize];
+
+  if (offsetof_safe(RH, GlobalRank) >= GH->RanksSize)
     return EffRank;
 
-  RankHeader *RH = (RankHeader *) &FH.getHeaderCache()[GH->RanksStart +
-                                               RankIndex*GH->RanksSize];
-
   return (int) RH->GlobalRank;
 }
 
+size_t GenericIO::readNumElems(int EffRank) {
+  if (FH.isBigEndian())
+    return readNumElems<true>(EffRank);
+  return readNumElems<false>(EffRank);
+}
+
+template <bool IsBigEndian>
 size_t GenericIO::readNumElems(int EffRank) {
   if (EffRank == -1) {
@@ -1006,14 +1135,22 @@
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
 
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  size_t RankIndex = getRankIndex(EffRank, GH, RankMap, FH.getHeaderCache());
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  size_t RankIndex = getRankIndex<IsBigEndian>(EffRank, GH, RankMap, FH.getHeaderCache());
 
   assert(RankIndex < GH->NRanks && "Invalid rank specified");
 
-  RankHeader *RH = (RankHeader *) &FH.getHeaderCache()[GH->RanksStart +
+  RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->RanksStart +
                                                RankIndex*GH->RanksSize];
   return (size_t) RH->NElems;
 }
 
+void GenericIO::readCoords(int Coords[3], int EffRank) {
+  if (FH.isBigEndian())
+    readCoords<true>(Coords, EffRank);
+  else
+    readCoords<false>(Coords, EffRank);
+}
+
+template <bool IsBigEndian>
 void GenericIO::readCoords(int Coords[3], int EffRank) {
   if (EffRank == -1) {
@@ -1029,17 +1166,25 @@
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
 
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  size_t RankIndex = getRankIndex(EffRank, GH, RankMap, FH.getHeaderCache());
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  size_t RankIndex = getRankIndex<IsBigEndian>(EffRank, GH, RankMap, FH.getHeaderCache());
 
   assert(RankIndex < GH->NRanks && "Invalid rank specified");
 
-  RankHeader *RH = (RankHeader *) &FH.getHeaderCache()[GH->RanksStart +
+  RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->RanksStart +
                                                RankIndex*GH->RanksSize];
 
   std::copy(RH->Coords, RH->Coords + 3, Coords);
+}
+
+void GenericIO::readData(int EffRank, bool PrintStats, bool CollStats) {
+  if (FH.isBigEndian())
+    readData<true>(EffRank, PrintStats, CollStats);
+  else
+    readData<false>(EffRank, PrintStats, CollStats);
 }
 
 // Note: Errors from this function should be recoverable. This means that if
 // one rank throws an exception, then all ranks should.
+template <bool IsBigEndian>
 void GenericIO::readData(int EffRank, bool PrintStats, bool CollStats) {
   int Rank;
@@ -1057,10 +1202,10 @@
     EffRank = Rank;
 
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
-  size_t RankIndex = getRankIndex(EffRank, GH, RankMap, FH.getHeaderCache());
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
+  size_t RankIndex = getRankIndex<IsBigEndian>(EffRank, GH, RankMap, FH.getHeaderCache());
 
   assert(RankIndex < GH->NRanks && "Invalid rank specified");
 
-  RankHeader *RH = (RankHeader *) &FH.getHeaderCache()[GH->RanksStart +
+  RankHeader<IsBigEndian> *RH = (RankHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->RanksStart +
                                                RankIndex*GH->RanksSize];
 
@@ -1077,5 +1222,5 @@
     bool VarFound = false;
     for (uint64_t j = 0; j < GH->NVars; ++j) {
-      VariableHeader *VH = (VariableHeader *) &FH.getHeaderCache()[GH->VarsStart +
+      VariableHeader<IsBigEndian> *VH = (VariableHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->VarsStart +
                                                            j*GH->VarsSize];
 
@@ -1121,7 +1266,7 @@
       void *Data = Vars[i].Data;
       bool HasExtraSpace = Vars[i].HasExtraSpace;
-      if (offsetof(GlobalHeader, BlocksStart) < GH->GlobalHeaderSize &&
+      if (offsetof_safe(GH, BlocksStart) < GH->GlobalHeaderSize &&
           GH->BlocksSize > 0) {
-        BlockHeader *BH = (BlockHeader *)
+        BlockHeader<IsBigEndian> *BH = (BlockHeader<IsBigEndian> *)
           &FH.getHeaderCache()[GH->BlocksStart +
                                (RankIndex*GH->NVars + j)*GH->BlocksSize];
@@ -1240,5 +1385,5 @@
 
       if (LData.size()) {
-        CompressHeader *CH = (CompressHeader*) &LData[0];
+        CompressHeader<IsBigEndian> *CH = (CompressHeader<IsBigEndian>*) &LData[0];
 
 #ifdef _OPENMP
@@ -1257,5 +1402,5 @@
 #endif
 
-        blosc_decompress(&LData[0] + sizeof(CompressHeader),
+        blosc_decompress(&LData[0] + sizeof(CompressHeader<IsBigEndian>),
                          Vars[i].Data, Vars[i].Size*RH->NElems);
 
@@ -1265,4 +1410,11 @@
         }
       }
+
+      // Byte swap the data if necessary.
+      if (IsBigEndian != isBigEndian())
+        for (size_t j = 0; j < RH->NElems; ++j) {
+          char *Offset = ((char *) Vars[i].Data) + j*Vars[i].Size;
+          bswap(Offset, Vars[i].Size);
+        }
 
       break;
@@ -1352,9 +1504,17 @@
 
 void GenericIO::getVariableInfo(vector<VariableInfo> &VI) {
+  if (FH.isBigEndian())
+    getVariableInfo<true>(VI);
+  else
+    getVariableInfo<false>(VI);
+}
+
+template <bool IsBigEndian>
+void GenericIO::getVariableInfo(vector<VariableInfo> &VI) {
   assert(FH.getHeaderCache().size() && "HeaderCache must not be empty");
 
-  GlobalHeader *GH = (GlobalHeader *) &FH.getHeaderCache()[0];
+  GlobalHeader<IsBigEndian> *GH = (GlobalHeader<IsBigEndian> *) &FH.getHeaderCache()[0];
   for (uint64_t j = 0; j < GH->NVars; ++j) {
-    VariableHeader *VH = (VariableHeader *) &FH.getHeaderCache()[GH->VarsStart +
+    VariableHeader<IsBigEndian> *VH = (VariableHeader<IsBigEndian> *) &FH.getHeaderCache()[GH->VarsStart +
                                                          j*GH->VarsSize];
 
Index: GenericIO.h
===================================================================
--- GenericIO.h	(revision da65757e00f1d262bf6da9c45b4a33e8b80b8e88)
+++ GenericIO.h	(revision a4fee139105de3bf748818b08fe85b87b6d2bf56)
@@ -288,5 +288,5 @@
   int readGlobalRankNumber(int EffRank = -1);
 
- void readData(int EffRank = -1, bool PrintStats = true, bool CollStats = true);
+  void readData(int EffRank = -1, bool PrintStats = true, bool CollStats = true);
 
   void close() {
@@ -319,4 +319,48 @@
   }
 #endif
+
+private:
+  // Implementation functions templated on the Endianness of the underlying
+  // data.
+
+#ifndef GENERICIO_NO_MPI
+  template <bool IsBigEndian>
+  void write();
+#endif
+
+  template <bool IsBigEndian>
+  void readHeaderLeader(void *GHPtr, bool MustMatch, int SplitNRanks,
+                        std::string &LocalFileName, uint64_t &HeaderSize,
+                        std::vector<char> &Header);
+
+  template <bool IsBigEndian>
+  int readNRanks();
+
+  template <bool IsBigEndian>
+  void readDims(int Dims[3]);
+
+  template <bool IsBigEndian>
+  uint64_t readTotalNumElems();
+
+  template <bool IsBigEndian>
+  void readPhysOrigin(double Origin[3]);
+
+  template <bool IsBigEndian>
+  void readPhysScale(double Scale[3]);
+
+  template <bool IsBigEndian>
+  int readGlobalRankNumber(int EffRank);
+
+  template <bool IsBigEndian>
+  size_t readNumElems(int EffRank);
+
+  template <bool IsBigEndian>
+  void readCoords(int Coords[3], int EffRank);
+
+  template <bool IsBigEndian>
+  void readData(int EffRank, bool PrintStats, bool CollStats);
+
+  template <bool IsBigEndian>
+  void getVariableInfo(std::vector<VariableInfo> &VI);
 
 protected:
@@ -378,4 +422,12 @@
     }
 
+    bool isBigEndian() {
+      return CountedFH ? CountedFH->IsBigEndian : false;
+    }
+
+    void setIsBigEndian(bool isBE) {
+      CountedFH->IsBigEndian = isBE;
+    }
+
     void allocate() {
       close();
@@ -393,5 +445,5 @@
 
     struct FHWCnt {
-      FHWCnt() : GFIO(0), Cnt(1) {}
+      FHWCnt() : GFIO(0), Cnt(1), IsBigEndian(false) {}
 
       ~FHWCnt() {
@@ -411,4 +463,5 @@
       // Used for reading
       std::vector<char> HeaderCache;
+      bool IsBigEndian;
     };
 
