Added support for big-endian architectures.

New support seems OK so far for me, but I want to test it a bit more
before making an official 0.3.5 release....
diff --git a/gpt.cc b/gpt.cc
index 4fdc5fc..19246fe 100644
--- a/gpt.cc
+++ b/gpt.cc
@@ -182,13 +182,11 @@
 
       switch (UseWhichPartitions()) {
          case use_mbr:
-//            printf("In LoadPartitions(), using MBR\n");
             XFormPartitions(&protectiveMBR);
             break;
          case use_gpt:
             break;
          case use_new:
-//            printf("In LoadPartitions(), making new\n");
             ClearGPTData();
             protectiveMBR.MakeProtectiveMBR();
             break;
@@ -230,6 +228,8 @@
    lseek64(fd, 512, SEEK_SET);
    read(fd, &mainHeader, 512); // read main GPT header
    mainCrcOk = CheckHeaderCRC(&mainHeader);
+   if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
+      ReverseHeaderBytes(&mainHeader);
 
    // Load backup header, check its CRC, and store the results of
    // the check for future reference
@@ -237,6 +237,8 @@
    if (lseek64(fd, seekTo, SEEK_SET) != (off_t) -1) {
       read(fd, &secondHeader, 512); // read secondary GPT header
       secondCrcOk = CheckHeaderCRC(&secondHeader);
+      if (IsLittleEndian() == 0) // big-endian system; adjust header byte order....
+         ReverseHeaderBytes(&secondHeader);
    } else {
       allOK = 0;
       state = gpt_invalid;
@@ -319,6 +321,8 @@
       read(fd, partitions, sizeOfParts);
       newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
       mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
+      if (IsLittleEndian() == 0)
+         ReversePartitionBytes();
       retval = 1;
    } // if
    return retval;
@@ -334,7 +338,7 @@
 
    mbrState = protectiveMBR.GetValidity();
 
-   if ((state == gpt_invalid) && (mbrState == mbr)) {
+   if ((state == gpt_invalid) && ((mbrState == mbr) || (mbrState == hybrid))) {
       printf("\n\a***************************************************************\n"
                     "Found invalid GPT and valid MBR; converting MBR to GPT format.\n"
              "THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Exit by typing 'q' if\n"
@@ -342,10 +346,16 @@
              "***************************************************************\n\n");
       which = use_mbr;
    } // if
+
    if ((state == gpt_valid) && (mbrState == gpt)) {
       printf("Found valid GPT with protective MBR; using GPT.\n");
       which = use_gpt;
    } // if
+   if ((state == gpt_valid) && (mbrState == hybrid)) {
+      printf("Found valid GPT with hybrid MBR; using GPT.\n");
+      printf("\aIf you change GPT partitions' sizes, you may need to re-create the hybrid MBR!\n");
+      which = use_gpt;
+   } // if
    if ((state == gpt_valid) && (mbrState == invalid)) {
       printf("\aFound valid GPT with corrupt MBR; using GPT and will create new\nprotective MBR on save.\n");
       which = use_gpt;
@@ -366,7 +376,7 @@
    // Nasty decisions here -- GPT is present, but corrupt (bad CRCs or other
    // problems)
    if (state == gpt_corrupt) {
-      if (mbrState == mbr) {
+      if ((mbrState == mbr) || (mbrState == hybrid)) {
          printf("Found valid MBR and corrupt GPT. Which do you want to use? (Using the\n"
                 "GPT MAY permit recovery of GPT data.)\n");
          answer = GetNumber(1, 3, 2, (char*) " 1 - MBR\n 2 - GPT\n 3 - Create blank GPT\n\nYour answer: ");
@@ -383,13 +393,13 @@
          if (answer == 1) {
             which = use_gpt;
          } else which = use_new;
-      } else {
+      } else { // corrupt GPT, MBR indicates it's a GPT disk....
          printf("\a\a****************************************************************************\n"
                 "Caution: Found protective or hybrid MBR and corrupt GPT. Using GPT, but disk\n"
                 "verification and recovery are STRONGLY recommended.\n"
                 "****************************************************************************\n");
-      } // if
-   } // if
+      } // if/else/else
+   } // if (corrupt GPT)
 
    if (which == use_new)
       printf("Creating new GPT entries.\n");
@@ -717,14 +727,11 @@
    else
       numToConvert = mainHeader.numParts;
 
-//   printf("In XFormPartitions(), numToConvert = %d\n", numToConvert);
-
    for (i = 0; i < numToConvert; i++) {
       origType = origParts->GetType(i);
-//      printf("Converting partition of type 0x%02X\n", (int) origType);
 
-      // don't convert extended partitions or null (non-existent) partitions
-      if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x00)) {
+      // don't convert extended, hybrid protective, or null (non-existent) partitions
+      if ((origType != 0x05) && (origType != 0x0f) && (origType != 0x00) && (origType != 0xEE)) {
          partitions[i].firstLBA = (uint64_t) origParts->GetFirstSector(i);
          partitions[i].lastLBA = partitions[i].firstLBA + (uint64_t)
                                  origParts->GetLength(i) - 1;
@@ -1034,16 +1041,29 @@
              (unsigned long) mainHeader.revision, UINT32_C(0x00010000));
    } // if/else/if
 
+   // If MBR bad, check for an Apple disk signature
+   if ((protectiveMBR.GetValidity() == invalid) && 
+       (((mainHeader.signature << 32) == APM_SIGNATURE1) ||
+        (mainHeader.signature << 32) == APM_SIGNATURE2)) {
+      printf("\n*******************************************************************\n");
+      printf("This disk appears to contain an Apple-format (APM) partition table!\n");
+      printf("*******************************************************************\n\n\a");
+   } // if
+
    return valid;
 } // GPTData::CheckHeaderValidity()
 
 // Check the header CRC to see if it's OK...
+// Note: Must be called BEFORE byte-order reversal on big-endian
+// systems!
 int GPTData::CheckHeaderCRC(struct GPTHeader* header) {
    uint32_t oldCRC, newCRC;
 
-   // Back up old header and then blank it, since it must be 0 for
+   // Back up old header CRC and then blank it, since it must be 0 for
    // computation to be valid
    oldCRC = header->headerCRC;
+   if (IsLittleEndian() == 0)
+      ReverseBytes((char*) &oldCRC, 4);
    header->headerCRC = UINT32_C(0);
 
    // Initialize CRC functions...
@@ -1055,18 +1075,29 @@
    return (oldCRC == newCRC);
 } // GPTData::CheckHeaderCRC()
 
-// Recompute all the CRCs. Must be called before saving if any changes
-// have been made.
+// Recompute all the CRCs. Must be called before saving (but after reversing
+// byte order on big-endian systems) if any changes have been made.
 void GPTData::RecomputeCRCs(void) {
    uint32_t crc;
+   uint32_t trueNumParts, crcTemp;
+   int littleEndian = 1;
 
    // Initialize CRC functions...
    chksum_crc32gentab();
 
+   littleEndian = IsLittleEndian();
+
    // Compute CRC of partition tables & store in main and secondary headers
-   crc = chksum_crc32((unsigned char*) partitions, mainHeader.numParts * GPT_SIZE);
+   trueNumParts = mainHeader.numParts;
+   if (littleEndian == 0)
+      ReverseBytes((char*) &trueNumParts, 4); // unreverse this key piece of data....
+   crc = chksum_crc32((unsigned char*) partitions, trueNumParts * GPT_SIZE);
    mainHeader.partitionEntriesCRC = crc;
    secondHeader.partitionEntriesCRC = crc;
+   if (littleEndian == 0) {
+      ReverseBytes((char*) &mainHeader.partitionEntriesCRC, 4);
+      ReverseBytes((char*) &secondHeader.partitionEntriesCRC, 4);
+   } // if
 
    // Zero out GPT tables' own CRCs (required for correct computation)
    mainHeader.headerCRC = 0;
@@ -1074,8 +1105,12 @@
 
    // Compute & store CRCs of main & secondary headers...
    crc = chksum_crc32((unsigned char*) &mainHeader, HEADER_SIZE);
+   if (littleEndian == 0)
+      ReverseBytes((char*) &crc, 4);
    mainHeader.headerCRC = crc;
    crc = chksum_crc32((unsigned char*) &secondHeader, HEADER_SIZE);
+   if (littleEndian == 0)
+      ReverseBytes((char*) &crc, 4);
    secondHeader.headerCRC = crc;
 } // GPTData::RecomputeCRCs()
 
@@ -1271,6 +1306,8 @@
          newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
          secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
 	 mainPartsCrcOk = secondPartsCrcOk;
+         if (IsLittleEndian() == 0)
+            ReversePartitionBytes();
          if (!secondPartsCrcOk) {
             printf("Error! After loading backup partitions, the CRC still doesn't check out!\n");
          } // if
@@ -1424,6 +1461,7 @@
    char answer, line[256];
    int fd;
    uint64_t secondTable;
+   uint32_t numParts;
    off_t offset;
 
    if (strlen(device) == 0) {
@@ -1463,6 +1501,17 @@
       } // for j...
    } // for i...
 
+   // Pull out some data that's needed before doing byte-order reversal on
+   // big-endian systems....
+   numParts = mainHeader.numParts;
+   secondTable = secondHeader.partitionEntriesLBA;
+   if (IsLittleEndian() == 0) {
+      // Reverse partition bytes first, since that function requires non-reversed
+      // data from the main header....
+      ReversePartitionBytes();
+      ReverseHeaderBytes(&mainHeader);
+      ReverseHeaderBytes(&secondHeader);
+   } // if
    RecomputeCRCs();
 
    if (allOK) {
@@ -1499,13 +1548,12 @@
 
          // Now write the main partition tables...
 	 if (allOK) {
-	    if (write(fd, partitions, GPT_SIZE * mainHeader.numParts) == -1)
+	    if (write(fd, partitions, GPT_SIZE * numParts) == -1)
                allOK = 0;
          } // if
 
          // Now seek to near the end to write the secondary GPT....
 	 if (allOK) {
-            secondTable = secondHeader.partitionEntriesLBA;
             offset = (off_t) secondTable * (off_t) (blockSize);
             if (lseek64(fd, offset, SEEK_SET) == (off_t) - 1) {
                allOK = 0;
@@ -1515,7 +1563,7 @@
 
          // Now write the secondary partition tables....
 	 if (allOK)
-            if (write(fd, partitions, GPT_SIZE * mainHeader.numParts) == -1)
+            if (write(fd, partitions, GPT_SIZE * numParts) == -1)
                allOK = 0;
 
          // Now write the secondary GPT header...
@@ -1558,6 +1606,14 @@
       printf("Aborting write of new partition table.\n");
    } // if
 
+   if (IsLittleEndian() == 0) {
+      // Reverse (normalize) header bytes first, since ReversePartitionBytes()
+      // requires non-reversed data in mainHeader...
+      ReverseHeaderBytes(&mainHeader);
+      ReverseHeaderBytes(&secondHeader);
+      ReversePartitionBytes();
+   } // if
+
    return (allOK);
 } // GPTData::SaveGPTData()
 
@@ -1568,10 +1624,19 @@
 // table; it discards the backup partition table, since it should be
 // identical to the main partition table on healthy disks.
 int GPTData::SaveGPTBackup(char* filename) {
-   int fd, allOK = 1;;
+   int fd, allOK = 1;
+   uint32_t numParts;
 
    if ((fd = open(filename, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) {
-      // First, write the protective MBR...
+      // Reverse the byte order, if necessary....
+      numParts = mainHeader.numParts;
+      if (IsLittleEndian() == 0) {
+         ReversePartitionBytes();
+         ReverseHeaderBytes(&mainHeader);
+         ReverseHeaderBytes(&secondHeader);
+      } // if
+
+      // Now write the protective MBR...
       protectiveMBR.WriteMBRData(fd);
 
       // Now write the main GPT header...
@@ -1586,7 +1651,7 @@
 
       // Now write the main partition tables...
       if (allOK) {
-         if (write(fd, partitions, GPT_SIZE * mainHeader.numParts) == -1)
+         if (write(fd, partitions, GPT_SIZE * numParts) == -1)
             allOK = 0;
       } // if
 
@@ -1597,6 +1662,13 @@
          printf("It may not be useable!\n");
       } // if/else
       close(fd);
+
+      // Now reverse the byte-order reversal, if necessary....
+      if (IsLittleEndian() == 0) {
+         ReverseHeaderBytes(&mainHeader);
+         ReverseHeaderBytes(&secondHeader);
+         ReversePartitionBytes();
+      } // if
    } else {
       fprintf(stderr, "Unable to open file %s for writing! Aborting!\n", filename);
       allOK = 0;
@@ -1611,8 +1683,12 @@
 int GPTData::LoadGPTBackup(char* filename) {
    int fd, allOK = 1, val;
    uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC;
+   int littleEndian = 1;
 
    if ((fd = open(filename, O_RDONLY)) != -1) {
+      if (IsLittleEndian() == 0)
+         littleEndian = 0;
+
       // Let the MBRData class load the saved MBR...
       protectiveMBR.ReadMBRData(fd);
 
@@ -1621,11 +1697,21 @@
       read(fd, &mainHeader, 512);
       mainCrcOk = CheckHeaderCRC(&mainHeader);
 
+      // Reverse byte order, if necessary
+      if (littleEndian == 0) {
+         ReverseHeaderBytes(&mainHeader);
+      } // if
+
       // Load the backup GPT header in much the same way as the main
       // GPT header....
       read(fd, &secondHeader, 512);
       secondCrcOk = CheckHeaderCRC(&secondHeader);
 
+      // Reverse byte order, if necessary
+      if (littleEndian == 0) {
+         ReverseHeaderBytes(&secondHeader);
+      } // if
+
       // Return valid headers code: 0 = both headers bad; 1 = main header
       // good, backup bad; 2 = backup header good, main header bad;
       // 3 = both headers good. Note these codes refer to valid GPT
@@ -1660,6 +1746,11 @@
          newCRC = chksum_crc32((unsigned char*) partitions, sizeOfParts);
          mainPartsCrcOk = (newCRC == mainHeader.partitionEntriesCRC);
          secondPartsCrcOk = (newCRC == secondHeader.partitionEntriesCRC);
+         // Reverse byte order, if necessary
+            if (littleEndian == 0) {
+               ReversePartitionBytes();
+            } // if
+
       } else {
          allOK = 0;
       } // if/else
@@ -1722,16 +1813,60 @@
    return (goOn == 'Y');
 } // GPTData::DestroyGPT()
 
+void GPTData::ReverseHeaderBytes(struct GPTHeader* header) {
+   ReverseBytes((char*) &header->signature, 8);
+   ReverseBytes((char*) &header->revision, 4);
+   ReverseBytes((char*) &header->headerSize, 4);
+   ReverseBytes((char*) &header->headerCRC, 4);
+   ReverseBytes((char*) &header->reserved, 4);
+   ReverseBytes((char*) &header->currentLBA, 8);
+   ReverseBytes((char*) &header->backupLBA, 8);
+   ReverseBytes((char*) &header->firstUsableLBA, 8);
+   ReverseBytes((char*) &header->lastUsableLBA, 8);
+   ReverseBytes((char*) &header->partitionEntriesLBA, 8);
+   ReverseBytes((char*) &header->numParts, 4);
+   ReverseBytes((char*) &header->sizeOfPartitionEntries, 4);
+   ReverseBytes((char*) &header->partitionEntriesCRC, 4);
+   ReverseBytes((char*) header->reserved2, GPT_RESERVED);
+   ReverseBytes((char*) &header->diskGUID.data1, 8);
+   ReverseBytes((char*) &header->diskGUID.data2, 8);
+} // GPTData::ReverseHeaderBytes()
+
+// IMPORTANT NOTE: This function requires non-reversed mainHeader
+// structure!
+void GPTData::ReversePartitionBytes() {
+   uint32_t i;
+
+   // Check GPT signature on big-endian systems; this will mismatch
+   // if the function is called out of order. Unfortunately, it'll also
+   // mismatch if there's data corruption.
+   if ((mainHeader.signature != GPT_SIGNATURE) && (IsLittleEndian() == 0)) {
+      printf("GPT signature mismatch in GPTData::ReversePartitionBytes(). This indicates\n"
+             "data corruption or a misplaced call to this function.\n");
+   } // if signature mismatch....
+   for (i = 0; i < mainHeader.numParts; i++) {
+      ReverseBytes((char*) &partitions[i].partitionType.data1, 8);
+      ReverseBytes((char*) &partitions[i].partitionType.data2, 8);
+      ReverseBytes((char*) &partitions[i].uniqueGUID.data1, 8);
+      ReverseBytes((char*) &partitions[i].uniqueGUID.data2, 8);
+      ReverseBytes((char*) &partitions[i].firstLBA, 8);
+      ReverseBytes((char*) &partitions[i].lastLBA, 8);
+      ReverseBytes((char*) &partitions[i].attributes, 8);
+   } // for
+} // GPTData::ReversePartitionBytes()
+
+/******************************************
+ *                                        *
+ * Additional non-class support functions *
+ *                                        *
+ ******************************************/
+
 // Check to be sure that data type sizes are correct. The basic types (uint*_t) should
 // never fail these tests, but the struct types may fail depending on compile options.
 // Specifically, the -fpack-struct option to gcc may be required to ensure proper structure
 // sizes.
 int SizesOK(void) {
    int allOK = 1;
-   union {
-      uint32_t num;
-      unsigned char uc[sizeof(uint32_t)];
-   } endian;
 
    if (sizeof(uint8_t) != 1) {
       fprintf(stderr, "uint8_t is %d bytes, should be 1 byte; aborting!\n", sizeof(uint8_t));
@@ -1762,11 +1897,10 @@
       allOK = 0;
    } // if
    // Determine endianness; set allOK = 0 if running on big-endian hardware
-   endian.num = 1;
-   if (endian.uc[0] != (unsigned char) 1) {
-      fprintf(stderr, "Running on big-endian hardware, but this program only works on little-endian\n"
-                      "systems; aborting!\n");
-      allOK = 0;
+   if (IsLittleEndian() == 0) {
+      fprintf(stderr, "\aRunning on big-endian hardware. Big-endian support is new and poorly"
+              " tested!\nBeware!\n");
+      // allOK = 0;
    } // if
    return (allOK);
 } // SizesOK()