home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1997 August / macformat-053.iso / mac / Shareware Plus / Developers / RCompare / RCompare.cpp < prev    next >
Encoding:
Text File  |  1997-05-07  |  42.3 KB  |  1,399 lines  |  [TEXT/MPS ]

  1. //*********************************************************************************************
  2. //
  3. //        File:                RCompare.cp
  4. //        Project:            MPW Tool
  5. //        Description:    Compares resources between two files
  6. //        History:            v. 1.0.0 - Rajko Furlan
  7. //
  8. //        Copyright © 1994 by Creative Synergies
  9. //        All Rights Reserved.
  10. //
  11. //*********************************************************************************************
  12.  
  13. #include    <CType.h>
  14. #include    <Dialogs.h>
  15. #include    <Errors.h>
  16. #include    <Files.h>
  17. #include    <Memory.h>
  18. #include    <Menus.h>
  19. #include    <Resources.h>
  20. #include    <Stdio.h>
  21. #include    <String.h>
  22. #include    <Strings.h>
  23.  
  24. //=============================================================================================
  25. //        CONSTANTS 
  26.  
  27. char*        Usage1            = "\
  28. ### Usage: %s -options file1 file2\n\
  29.    \n\
  30.    By default compares resource types and IDs, but not contents.\n\
  31.     It also compares number of items in 'CMNU', 'MENU', 'STR#', & 'DITL' resources.\n\
  32.    \n\
  33.     Following options are available:\n\
  34.        -a   compares contents of all resources\n\
  35.         -d   compares 'DITL' bounding rects & items\n";
  36.  
  37. char*        Usage2            = "\
  38.         -dd  compares 'DITL' data only (i.e. without strings)\n\
  39.         -m   compares 'MENU' & 'CMNU' header, title, items & attrs\n\
  40.         -md  compares 'MENU' & 'CMNU' data only (i.e. without strings)\n\
  41.         -s   compares 'STR ' & 'STR#' strings\n\
  42.         -v   compares 'View' contents\n\
  43.         -o   compares contents of all other resources except those above\n\
  44.         -nt  no extra types are reported\n\
  45.         -ni  no extra IDs are reported\n\
  46.         -nc  don't compare 'CODE' resources (used with -a or -o)\n";
  47.  
  48. char*        OpenError        = "### %s - Unable to open file %s.\n";
  49. char*        FilesMatch        = "*** Files match ***\n";
  50. char*        FilePathStr        = "File #%d: %s\n";
  51. char*        File1Str            = "1st";
  52. char*        File2Str            = "2nd";
  53. char*        ExtraTypes        = "Extra types in %s:\n";
  54. char*        ExtraResIDs        = "Extra resources in %s:\n";
  55. char*        ExtraStrings    = "Extra strings in 'STR#' resources in %s:\n";
  56. char*        ExtraDItems        = "Extra items in 'DITL' resources in %s:\n";
  57. char*        ExtraCMItems    = "Extra items in 'CMNU' resources in %s:\n";
  58. char*        ExtraMItems        = "Extra items in 'MENU' resources in %s:\n";
  59. char*        BadResources    = "Nonmatching resources:\n";
  60. char*        BadDItems        = "Nonmatching items in 'DITL' resources:\n";
  61. char*        BadCMItems        = "Nonmatching items in 'CMNU' resources:\n";
  62. char*        BadMItems        = "Nonmatching items in 'MENU' resources:\n";
  63. char*        BadLStrings        = "Nonmatching strings in 'STR#' resources:\n";
  64. char*        BadStrings        = "Nonmatching strings in 'STR ' resources:\n";
  65. char*        BadViews            = "Nonmatching views:\n";
  66.  
  67. char*        TypeStr            = "   '%s'\n";
  68. char*        TypeIDStr        = "   '%s' (%d)\n";
  69. char*        TypeIDExtraSStr= "   '%s' (%d) - %d extra string(s)\n";
  70. char*        TypeIDExtraIStr= "   '%s' (%d) - %d extra items(s)\n";
  71. char*        TypeIDMenuStr    = "   '%s' (%d, title)\n";
  72. char*        ItemStr            = "      item %d\n";
  73. char*        HeaderStr        = "      header\n";
  74. char*        TitleStr            = "      title\n";
  75. char*        DItemsMismatch    = "         items are of different kinds - following items ignored!\n";
  76. char*        DRectStateStr    = "         \"%s\" - (rect = %4d,%4d,%4d,%4d; %8s)\n";
  77. char*        DRectStateIDStr= "         \"%s\" - (rect = %4d,%4d,%4d,%4d; %8s; resID = %5d)\n";
  78. char*        StringStr        = "         \"%s\"\n";
  79. char*        MenuHeaderStr    = "         menuID = %5d,  menuProc = %5d,  enableFlags = %#8x;\n";
  80. char*        MenuCmdStr        = "         \"%s\" - (cmd = %5d)\n";
  81. char*        MenuAttrsStr    = "         \"%s\" - (icon = %3d, key = %3d, mark = %3d, style = %3d)\n";
  82. char*        MenuCmdAttrsStr= "         \"%s\" - (cmd = %5d, icon = %3d, key = %3d, mark = %3d, style = %3d)\n";
  83. char*        EnabledStr        = "enabled";
  84. char*        DisabledStr        = "disabled";
  85.  
  86. enum {
  87.     kCompareResIDs1,
  88.     kCompareResIDs2,
  89.     kCompareDITLs,
  90.     kCompareMenus,
  91.     kCompareStrings,
  92.     kCompareViews,
  93.     kCompareOther
  94. };
  95.  
  96. //=============================================================================================
  97. //        TYPES
  98.  
  99. typedef short ResID;
  100. typedef void (*DoCompare) (short ref1Num, short ref2Num,
  101.                                     ResType resType, ResID resID, char* resTypeStr,
  102.                                     Boolean& headerWritten, short firstFile);
  103.  
  104. //=============================================================================================
  105. //        EXTERNALS 
  106.  
  107. extern    pascal void RotateCursor (long);
  108.  
  109. //=============================================================================================
  110. //        DECLARATIONS 
  111.  
  112. static void        DoTheJob (short ref1Num, short ref2Num, Boolean compareDITLs, Boolean compareMenus,
  113.                                     Boolean compareStrings, Boolean compareViews, Boolean compareOther,
  114.                                     Boolean extraTypes, Boolean extraIDs);
  115. static void        CompareTypes (ResType** types1TableH, ResType** types2TableH,
  116.                                         short types1Count, short types2Count, short firstFile);
  117. static void        CompareResIDs (ResType resType, ResID** res1TableH, ResID** res2TableH,
  118.                                         short res1Count, short res2Count, short firstFile,
  119.                                         Boolean& headerWritten);
  120. static void        CompareDITLs (short ref1Num, short ref2Num,
  121.                                         ResType resType, ResID resID, char* resTypeStr,
  122.                                         Boolean& headerWritten, short firstFile);
  123. static void        CompareDITLItems (short ref1Num, short ref2Num,
  124.                                             ResType resType, ResID resID, char* resTypeStr,
  125.                                             Boolean& headerWritten, short firstFile);
  126. static void        WriteDITLTypeIDItemStr (char* resTypeStr, ResID resID, short item,
  127.                                                     Boolean& headerWritten, Boolean& idWritten);
  128. static void        CompareMenus (short ref1Num, short ref2Num,
  129.                                         ResType resType, ResID resID, char* resTypeStr,
  130.                                         Boolean& headerWritten, short firstFile);
  131. static void        CompareMenuItems (short ref1Num, short ref2Num,
  132.                                             ResType resType, ResID resID, char* resTypeStr,
  133.                                             Boolean& headerWritten, short firstFile);
  134. static void        CompareStringLists (short ref1Num, short ref2Num,
  135.                                                 ResType resType, ResID resID, char* resTypeStr,
  136.                                                 Boolean& headerWritten, short firstFile);
  137. static void        CompareStrings (short ref1Num, short ref2Num,
  138.                                             ResType resType, ResID resID, char* resTypeStr,
  139.                                             Boolean& headerWritten, short firstFile);
  140. static void        CompareViews (short ref1Num, short ref2Num,
  141.                                         ResType resType, ResID resID, char* resTypeStr,
  142.                                         Boolean& headerWritten, short firstFile);
  143. static void        CompareGeneric (short ref1Num, short ref2Num,
  144.                                             ResType resType, ResID resID, char* resTypeStr,
  145.                                             Boolean& headerWritten, short firstFile);
  146. static void        IterateResIDs (short ref1Num, short ref2Num, ResType resType,
  147.                                         ResID** res1TableH, ResID** res2TableH,
  148.                                         short res1Count, short res2Count, short firstFile,
  149.                                         DoCompare doCompare, Boolean& headerWritten);
  150. static ResType**    BuildTypesTable (short refNum);
  151. static ResID**    BuildResIDsTable (short refNum, ResType resType);
  152. static void        BuildResIDsTables (short ref1Num, short ref2Num, ResType resType,
  153.                                             ResID**& res1TableH, ResID**& res2TableH,
  154.                                             short& res1Count, short& res2Count);
  155. static Handle    GetTheResource (short refNum, ResType resType, ResID resID);
  156. static short    SetResourceFile (short refNum);
  157. static void        ResType2str (char* resTypeStr, ResType resType);
  158. static short    RCCountMenuItems (Handle menuH, ResType resType);
  159.  
  160. //=============================================================================================
  161. //        GLOBALS 
  162.  
  163. Boolean    gFilesMatch = TRUE;
  164. Boolean    gMenuStrings = TRUE;
  165. Boolean    gDITLStrings = TRUE;
  166. Boolean    gCompareCODE = TRUE;
  167. long        gCursorCounter = 0;
  168.  
  169. //=============================================================================================
  170. //        CODE 
  171.  
  172. //---------------------------------------------------------------------------------------------
  173. // main:
  174. //---------------------------------------------------------------------------------------------
  175.  
  176. main (int argc, char* argv []) {
  177.     long    status = 0;
  178.     
  179.     if (argc >= 3) {
  180.         Str255 file1Name = "";
  181.         Str255 file2Name = "";
  182.         Boolean compareDITLs = FALSE;
  183.         Boolean compareMenus = FALSE;
  184.         Boolean compareStrings = FALSE;
  185.         Boolean compareViews = FALSE;
  186.         Boolean compareOther = FALSE;
  187.         Boolean extraTypes = TRUE;
  188.         Boolean extraIDs = TRUE;
  189.         Boolean file1NameOK = FALSE;
  190.         short ref1Num;
  191.         short ref2Num;
  192.         Ptr argFile1NamePtr;
  193.         Ptr argFile2NamePtr;
  194.         
  195.         RotateCursor (0);
  196.         
  197.         for (short i = 1; i < argc; i ++) {
  198.             short argLen = strlen (argv [i]);
  199.             Ptr argPtr = argv [i];
  200.             
  201.             if (*argPtr == '-') {
  202.                 char ch = tolower (*(argPtr + 1));
  203.                 char ch2 = tolower (*(argPtr + 2));
  204.                 
  205.                 if (ch == 'a') {
  206.                     compareDITLs = TRUE;
  207.                     compareMenus = TRUE;
  208.                     compareStrings = TRUE;
  209.                     compareViews = TRUE;
  210.                     compareOther = TRUE;
  211.                 }
  212.                 else if (ch == 'd') {
  213.                     compareDITLs = TRUE;
  214.                     
  215.                     if (ch2 == 'd')
  216.                         gDITLStrings = FALSE;
  217.                 }
  218.                 else if (ch == 'm') {
  219.                     compareMenus = TRUE;
  220.                     
  221.                     if (ch2 == 'd')
  222.                         gMenuStrings = FALSE;
  223.                 }
  224.                 else if (ch == 'o')
  225.                     compareOther = TRUE;
  226.                 else if (ch == 's')
  227.                     compareStrings = TRUE;
  228.                 else if (ch == 'v')
  229.                     compareViews = TRUE;
  230.                 else if (ch == 'n') {
  231.                     if (ch2 == 't')
  232.                         extraTypes = FALSE;
  233.                     else if (ch2 == 'i')
  234.                         extraIDs = FALSE;
  235.                     else if (ch2 == 'c')
  236.                         gCompareCODE = FALSE;
  237.                     else
  238.                         goto ShowUsage;
  239.                 }
  240.                 else
  241.                     goto ShowUsage;
  242.             }
  243.             else {
  244.                 if (! file1NameOK) {
  245.                     argFile1NamePtr = argPtr;
  246.                     memcpy (file1Name, argPtr, argLen + 1);
  247.                     c2pstr ((char*) &file1Name [0]);
  248.                     file1NameOK = TRUE;
  249.                 }
  250.                 else {
  251.                     argFile2NamePtr = argPtr;
  252.                     memcpy (file2Name, argPtr, argLen + 1);
  253.                     c2pstr ((char*) &file2Name [0]);
  254.                 }
  255.             }
  256.         }
  257.         
  258.         if ((file1Name [0] == 0) || (file2Name [0] == 0))
  259.             goto ShowUsage;
  260.         
  261.         short curRefNum = CurResFile ();
  262.         
  263.         FSSpec fileFSSpec;
  264.         if ((FSMakeFSSpec (0, 0, file1Name, &fileFSSpec) != noErr)
  265.         || ((ref1Num = FSpOpenResFile (&fileFSSpec, fsRdPerm)) == -1)) {
  266.             UseResFile (curRefNum);
  267.             
  268.             fprintf (stderr, OpenError, argv [0], argFile1NamePtr);
  269.             status = 2;
  270.         }
  271.         else if ((FSMakeFSSpec (0, 0, file2Name, &fileFSSpec) != noErr)
  272.               || ((ref2Num = FSpOpenResFile (&fileFSSpec, fsRdPerm)) == -1)) {
  273.             CloseResFile (ref1Num);
  274.             UseResFile (curRefNum);
  275.             
  276.             fprintf (stderr, OpenError, argv [0], argFile2NamePtr);
  277.             status = 2;
  278.         }
  279.         else {
  280.             UseResFile (curRefNum);
  281.             
  282.             p2cstr (file1Name);
  283.             p2cstr (file2Name);
  284.             fprintf (stderr, FilePathStr, 1, file1Name);
  285.             fprintf (stderr, FilePathStr, 2, file2Name);
  286.             fprintf (stderr, "\n");
  287.             
  288.             DoTheJob (ref1Num, ref2Num, compareDITLs, compareMenus, compareStrings,
  289.                             compareViews, compareOther, extraTypes, extraIDs);
  290.             CloseResFile (ref1Num);
  291.             CloseResFile (ref2Num);
  292.             
  293.             if (gFilesMatch)
  294.                 fprintf (stderr, FilesMatch);
  295.         }
  296.     }
  297.     else {
  298.  
  299. ShowUsage:
  300.         
  301.         fprintf (stderr, Usage1, argv [0]);
  302.         fprintf (stderr, Usage2);
  303.         status = 1;
  304.     }
  305.     
  306.     return (status);
  307.     
  308. } // main
  309.  
  310. //---------------------------------------------------------------------------------------------
  311. //    DoTheJob:
  312. //---------------------------------------------------------------------------------------------
  313.  
  314. static void DoTheJob (short ref1Num, short ref2Num, Boolean compareDITLs, Boolean compareMenus,
  315.                                 Boolean compareStrings, Boolean compareViews, Boolean compareOther,
  316.                                 Boolean extraTypes, Boolean extraIDs) {
  317.     
  318.     ResType** types1TableH = BuildTypesTable (ref1Num);
  319.     ResType** types2TableH = BuildTypesTable (ref2Num);
  320.     
  321.     short types1Count = (short) GetHandleSize ((Handle) types1TableH) / sizeof (ResType);
  322.     short types2Count = (short) GetHandleSize ((Handle) types2TableH) / sizeof (ResType);
  323.     
  324.     if (extraTypes) {
  325.         CompareTypes (types1TableH, types2TableH, types1Count, types2Count, 1);
  326.         CompareTypes (types2TableH, types1TableH, types2Count, types1Count, 2);
  327.     }
  328.     
  329.     for (short whatToDo = kCompareResIDs1; whatToDo <= kCompareOther; whatToDo ++) {
  330.         short index1 = 0;
  331.         short index2 = 0;
  332.         
  333.         Boolean headerWritten = FALSE;
  334.         
  335.         while ((index1 < types1Count) && (index2 < types2Count)) {
  336.             ResType resType = (*types1TableH) [index1];
  337.             
  338.             if (resType < (*types2TableH) [index2]) {
  339.                 // Extra type in table1
  340.                 index1 ++;
  341.             }
  342.             else if (resType > (*types2TableH) [index2]) {
  343.                 // Extra type in table2
  344.                 index2 ++;
  345.             }
  346.             else {
  347.                 ResID** res1TableH = NULL;
  348.                 ResID** res2TableH = NULL;
  349.                 short res1Count;
  350.                 short res2Count;
  351.                 
  352.                 switch (whatToDo) {
  353.                     case kCompareResIDs1:
  354.                         
  355.                         if (extraIDs) {
  356.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  357.                                                         res1Count, res2Count);
  358.                             CompareResIDs (resType, res1TableH, res2TableH, res1Count, res2Count, 1,
  359.                                                 headerWritten);
  360.                         }
  361.                         
  362.                         break;
  363.                     
  364.                     case kCompareResIDs2:
  365.                         
  366.                         if (extraIDs) {
  367.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  368.                                                         res1Count, res2Count);
  369.                             CompareResIDs (resType, res2TableH, res1TableH, res2Count, res1Count, 2,
  370.                                                 headerWritten);
  371.                         }
  372.                         
  373.                         break;
  374.                     
  375.                     case kCompareDITLs:
  376.                         
  377.                         if (resType == 'DITL') {
  378.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  379.                                                         res1Count, res2Count);
  380.                             IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  381.                                                 res1Count, res2Count, 1, CompareDITLs,
  382.                                                 headerWritten);
  383.                             IterateResIDs (ref2Num, ref1Num, resType, res2TableH, res1TableH,
  384.                                                 res2Count, res1Count, 2, CompareDITLs,
  385.                                                 headerWritten);
  386.                             
  387.                             if (compareDITLs)
  388.                                 IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  389.                                                     res1Count, res2Count, 0, CompareDITLItems,
  390.                                                     headerWritten);
  391.                             
  392.                             if (headerWritten) {
  393.                                 fprintf (stderr, "\n");
  394.                                 headerWritten = FALSE;
  395.                             }
  396.                         }
  397.                         
  398.                         break;
  399.                     
  400.                     case kCompareMenus:
  401.                         
  402.                         if ((resType == 'CMNU') || (resType == 'MENU')) {
  403.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  404.                                                         res1Count, res2Count);
  405.                             IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  406.                                                 res1Count, res2Count, 1, CompareMenus,
  407.                                                 headerWritten);
  408.                             IterateResIDs (ref2Num, ref1Num, resType, res2TableH, res1TableH,
  409.                                                 res2Count, res1Count, 2, CompareMenus,
  410.                                                 headerWritten);
  411.                             
  412.                             if (compareMenus)
  413.                                 IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  414.                                                     res1Count, res2Count, 0, CompareMenuItems,
  415.                                                     headerWritten);
  416.                             
  417.                             if (headerWritten) {
  418.                                 fprintf (stderr, "\n");
  419.                                 headerWritten = FALSE;
  420.                             }
  421.                         }
  422.                         
  423.                         break;
  424.                     
  425.                     case kCompareStrings:
  426.                         
  427.                         if ((resType == 'STR#') || (resType == 'STR ')) {
  428.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  429.                                                         res1Count, res2Count);
  430.                             
  431.                             if (resType == 'STR#') {
  432.                                 IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  433.                                                     res1Count, res2Count, 1, CompareStringLists,
  434.                                                     headerWritten);
  435.                                 IterateResIDs (ref2Num, ref1Num, resType, res2TableH, res1TableH,
  436.                                                     res2Count, res1Count, 2, CompareStringLists,
  437.                                                     headerWritten);
  438.                             }
  439.                             
  440.                             if (compareStrings)
  441.                                 IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  442.                                                     res1Count, res2Count, 0, CompareStrings,
  443.                                                     headerWritten);
  444.                             
  445.                             if (headerWritten) {
  446.                                 fprintf (stderr, "\n");
  447.                                 headerWritten = FALSE;
  448.                             }
  449.                         }
  450.                         
  451.                         break;
  452.                     
  453.                     case kCompareViews:
  454.                         
  455.                         if ((resType == 'View') && compareViews) {
  456.                             BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  457.                                                         res1Count, res2Count);
  458.                             IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  459.                                                 res1Count, res2Count, 0, CompareViews,
  460.                                                 headerWritten);
  461.                         }
  462.                         
  463.                         break;
  464.                     
  465.                     case kCompareOther:
  466.                         
  467.                         if (compareOther) {
  468.                             if ((resType != 'CMNU') && (resType != 'MENU')
  469.                             && (resType != 'STR#') && (resType != 'STR ')
  470.                             && (resType != 'View') && (resType != 'DITL')
  471.                             && ((resType != 'CODE') || gCompareCODE)) {
  472.                                 BuildResIDsTables (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  473.                                                             res1Count, res2Count);
  474.                                 IterateResIDs (ref1Num, ref2Num, resType, res1TableH, res2TableH,
  475.                                                     res1Count, res2Count, 0, CompareGeneric,
  476.                                                     headerWritten);
  477.                             }
  478.                         }
  479.                         
  480.                         break;
  481.                 }
  482.                 
  483.                 if (res1TableH)
  484.                     DisposeHandle ((Handle) res1TableH);
  485.                 if (res2TableH)
  486.                     DisposeHandle ((Handle) res2TableH);
  487.                 
  488.                 index1 ++;
  489.                 index2 ++;
  490.             }
  491.         }
  492.         
  493.         if (headerWritten)
  494.             fprintf (stderr, "\n");
  495.     }
  496.     
  497.     DisposeHandle ((Handle) types1TableH);
  498.     DisposeHandle ((Handle) types2TableH);
  499.     
  500. } // DoTheJob
  501.  
  502. //---------------------------------------------------------------------------------------------
  503. //    CompareTypes: Compares resource types in ordered tables.
  504. //---------------------------------------------------------------------------------------------
  505.  
  506. static void CompareTypes (ResType** types1TableH, ResType** types2TableH,
  507.                                     short types1Count, short types2Count, short firstFile) {
  508.     
  509.     Boolean headerWritten = FALSE;
  510.     short index1 = 0;
  511.     short index2 = 0;
  512.     
  513.     while (index1 < types1Count) {
  514.         RotateCursor (++ gCursorCounter);
  515.         ResType resType = (*types1TableH) [index1];
  516.         char resTypeStr [6];
  517.         
  518.         if ((index2 >= types2Count)
  519.         || (resType < (*types2TableH) [index2])) {
  520.             // Extra type in table1
  521.             if (! headerWritten) {
  522.                 fprintf (stderr, ExtraTypes, (firstFile == 1) ? File1Str : File2Str);
  523.                 headerWritten = TRUE;
  524.                 gFilesMatch = FALSE;
  525.             }
  526.             
  527.             ResType2str (resTypeStr, resType);
  528.             fprintf (stderr, TypeStr, resTypeStr);
  529.             
  530.             index1 ++;
  531.         }
  532.         else if (resType > (*types2TableH) [index2]) {
  533.             // Extra type in table2
  534.             index2 ++;
  535.         }
  536.         else {
  537.             index1 ++;
  538.             index2 ++;
  539.         }
  540.     }
  541.     
  542.     if (headerWritten)
  543.         fprintf (stderr, "\n");
  544.     
  545. } // CompareTypes
  546.  
  547. //---------------------------------------------------------------------------------------------
  548. //    CompareResIDs: Compares resource IDs in ordered tables.
  549. //---------------------------------------------------------------------------------------------
  550.  
  551. static void CompareResIDs (ResType resType, ResID** res1TableH, ResID** res2TableH,
  552.                                     short res1Count, short res2Count, short firstFile,
  553.                                     Boolean& headerWritten) {
  554.     
  555.     char resTypeStr [6];
  556.     ResType2str (resTypeStr, resType);
  557.     
  558.     short index1 = 0;
  559.     short index2 = 0;
  560.     
  561.     while (index1 < res1Count) {
  562.         RotateCursor (++ gCursorCounter);
  563.         ResID resID = (*res1TableH) [index1];
  564.         
  565.         if ((index2 >= res2Count)
  566.         || (resID < (*res2TableH) [index2])) {
  567.             // Extra ID in table1
  568.             if (! headerWritten) {
  569.                 fprintf (stderr, ExtraResIDs, (firstFile == 1) ? File1Str : File2Str);
  570.                 headerWritten = TRUE;
  571.                 gFilesMatch = FALSE;
  572.             }
  573.             
  574.             fprintf (stderr, TypeIDStr, resTypeStr, resID);
  575.             
  576.             index1 ++;
  577.         }
  578.         else if (resID > (*res2TableH) [index2]) {
  579.             // Extra ID in table2
  580.             index2 ++;
  581.         }
  582.         else {
  583.             index1 ++;
  584.             index2 ++;
  585.         }
  586.     }
  587.     
  588. } // CompareResIDs
  589.  
  590. //---------------------------------------------------------------------------------------------
  591. //    CompareDITLs: Compares number of items in 'DITL' resources with equal IDs.
  592. //---------------------------------------------------------------------------------------------
  593.  
  594. static void CompareDITLs (short ref1Num, short ref2Num,
  595.                                     ResType resType, ResID resID, char* resTypeStr,
  596.                                     Boolean& headerWritten, short firstFile) {
  597.     
  598.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  599.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  600.     
  601.     if (res1H && res2H) {
  602.         short item1Count = *(short*) *res1H;
  603.         short item2Count = *(short*) *res2H;
  604.         
  605.         if (item1Count > item2Count) {
  606.             if (! headerWritten) {
  607.                 fprintf (stderr, ExtraDItems, (firstFile == 1) ? File1Str : File2Str);
  608.                 headerWritten = TRUE;
  609.                 gFilesMatch = FALSE;
  610.             }
  611.             
  612.             fprintf (stderr, TypeIDExtraIStr, resTypeStr, resID, item1Count - item2Count);
  613.         }
  614.     }
  615.     
  616.     ReleaseResource (res1H);
  617.     ReleaseResource (res2H);
  618.     
  619. } // CompareDITLs
  620.  
  621. //---------------------------------------------------------------------------------------------
  622. //    CompareDITLItems: Compares corresponding 'DITL' items.
  623. //---------------------------------------------------------------------------------------------
  624.  
  625. static void CompareDITLItems (short ref1Num, short ref2Num,
  626.                                         ResType resType, ResID resID, char* resTypeStr,
  627.                                         Boolean& headerWritten, short /*firstFile*/) {
  628.     
  629.     // Template for items with a string
  630.     struct ItemData {
  631.         long        filler;
  632.         Rect        rect;
  633.         char        kind;
  634.         Str255    string;
  635.     };
  636.     
  637.     // Template for items with a resID
  638.     struct Item2Data {
  639.         long        filler;
  640.         Rect        rect;
  641.         char        kind;
  642.         char        what;
  643.         short        resID;
  644.     };
  645.     
  646.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  647.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  648.     
  649.     if (res1H && res2H) {
  650.         HLock (res1H);
  651.         HLock (res2H);
  652.         
  653.         Ptr pData1 = *res1H;
  654.         Ptr pData2 = *res2H;
  655.         
  656.         short item = 1;
  657.         short item1Count = *(short*) pData1;
  658.         short item2Count = *(short*) pData2;
  659.         pData1 += sizeof (short);
  660.         pData2 += sizeof (short);
  661.         
  662.         Boolean idWritten = FALSE;
  663.         
  664.         while ((item1Count >= 0) && (item2Count >= 0)) {
  665.             RotateCursor (++ gCursorCounter);
  666.             Str255 string;
  667.             
  668.             if ((*(ItemData*) pData1).kind != (*(ItemData*) pData2).kind) {
  669.                 if (! headerWritten) {
  670.                     fprintf (stderr, BadDItems);
  671.                     headerWritten = TRUE;
  672.                     gFilesMatch = FALSE;
  673.                 }
  674.                 
  675.                 if (! idWritten) {
  676.                     fprintf (stderr, TypeIDStr, resTypeStr, resID);
  677.                     idWritten = TRUE;
  678.                 }
  679.                 
  680.                 fprintf (stderr, ItemStr, item);
  681.                 fprintf (stderr, DItemsMismatch);
  682.                 break;
  683.             }
  684.             
  685.             Rect rect1 = (*(ItemData*) pData1).rect;
  686.             Rect rect2 = (*(ItemData*) pData2).rect;
  687.             
  688.             Boolean rectsDontMatch = ! EqualRect (&rect1, &rect2);
  689.             Boolean item1Enabled = ! ((*(ItemData*) pData1).kind & itemDisable);
  690.             Boolean item2Enabled = ! ((*(ItemData*) pData2).kind & itemDisable);
  691.             Boolean statesDontMatch = (item1Enabled != item2Enabled);
  692.             
  693.             switch ((*(ItemData*) pData1).kind & 0x7F) {
  694.                 case ctrlItem + btnCtrl:
  695.                 case ctrlItem + chkCtrl:
  696.                 case ctrlItem + radCtrl:
  697.                 case statText:
  698.                 case editText:
  699.                     
  700.                     Ptr str1 = (char*) (*(ItemData*) pData1).string;
  701.                     Ptr str2 = (char*) (*(ItemData*) pData2).string;
  702.                     
  703.                     Boolean stringsDontMatch = ((*str1 != *str2)
  704.                                                          || (memcmp (str1, str2, (unsigned char) *str1 + 1)));
  705.                     
  706.                     if ((gDITLStrings && stringsDontMatch)
  707.                     || (rectsDontMatch || statesDontMatch)) {
  708.                         WriteDITLTypeIDItemStr (resTypeStr, resID, item,
  709.                                                         headerWritten, idWritten);
  710.                         
  711.                         if (gDITLStrings)
  712.                             BlockMove (str1, string, (unsigned char) *str1 + 1);
  713.                         else
  714.                             string [0] = 0;
  715.                         p2cstr (string);
  716.                         
  717.                         if (rectsDontMatch || statesDontMatch)
  718.                             fprintf (stderr, DRectStateStr, string, rect1.top, rect1.left,
  719.                                         rect1.bottom, rect1.right,
  720.                                         (item1Enabled) ? EnabledStr : DisabledStr);
  721.                         else
  722.                             fprintf (stderr, StringStr, string);
  723.                         
  724.                         if (gDITLStrings)
  725.                             BlockMove (str2, string, (unsigned char) *str2 + 1);
  726.                         else
  727.                             string [0] = 0;
  728.                         p2cstr (string);
  729.                         
  730.                         if (rectsDontMatch || statesDontMatch)
  731.                             fprintf (stderr, DRectStateStr, string, rect2.top, rect2.left,
  732.                                         rect2.bottom, rect2.right,
  733.                                         (item2Enabled) ? EnabledStr : DisabledStr);
  734.                         else
  735.                             fprintf (stderr, StringStr, string);
  736.                     }
  737.                     
  738.                     pData1 = str1 + (unsigned char) *str1 + 1;
  739.                     pData2 = str2 + (unsigned char) *str2 + 1;
  740.                     break;
  741.                 
  742.                 case ctrlItem + resCtrl:
  743.                 case iconItem:
  744.                 case picItem:
  745.                     
  746.                     short resID1 = (*(Item2Data*) pData1).resID;
  747.                     short resID2 = (*(Item2Data*) pData2).resID;
  748.                     Boolean resIDsDontMatch = (resID1 != resID2);
  749.                     
  750.                     if (rectsDontMatch || statesDontMatch || resIDsDontMatch) {
  751.                         WriteDITLTypeIDItemStr (resTypeStr, resID, item,
  752.                                                         headerWritten, idWritten);
  753.                         string [0] = 0;
  754.                         
  755.                         fprintf (stderr, DRectStateIDStr, string, rect1.top, rect1.left,
  756.                                     rect1.bottom, rect1.right,
  757.                                     (item1Enabled) ? EnabledStr : DisabledStr, resID1);
  758.                         
  759.                         fprintf (stderr, DRectStateIDStr, string, rect2.top, rect2.left,
  760.                                     rect2.bottom, rect2.right,
  761.                                     (item2Enabled) ? EnabledStr : DisabledStr, resID2);
  762.                     }
  763.                     
  764.                     pData1 += sizeof (Item2Data);
  765.                     pData2 += sizeof (Item2Data);
  766.                     break;
  767.                 
  768.                 case userItem:
  769.                     
  770.                     if (rectsDontMatch || statesDontMatch) {
  771.                         WriteDITLTypeIDItemStr (resTypeStr, resID, item,
  772.                                                         headerWritten, idWritten);
  773.                         string [0] = 0;
  774.                         
  775.                         fprintf (stderr, DRectStateStr, string, rect1.top, rect1.left,
  776.                                     rect1.bottom, rect1.right,
  777.                                     (item1Enabled) ? EnabledStr : DisabledStr);
  778.                         
  779.                         fprintf (stderr, DRectStateStr, string, rect2.top, rect2.left,
  780.                                     rect2.bottom, rect2.right,
  781.                                     (item2Enabled) ? EnabledStr : DisabledStr);
  782.                     }
  783.                     
  784.                     pData1 += sizeof (Item2Data) - sizeof (short);    // no resID
  785.                     pData2 += sizeof (Item2Data) - sizeof (short);
  786.                     break;
  787.                 case 1:
  788.                     
  789.                     // Help Mgr type item (no constant yet)
  790.                     if (rectsDontMatch || statesDontMatch) {
  791.                         WriteDITLTypeIDItemStr (resTypeStr, resID, item,
  792.                                                         headerWritten, idWritten);
  793.                         string [0] = 0;
  794.                         
  795.                         fprintf (stderr, DRectStateStr, string, rect1.top, rect1.left,
  796.                                     rect1.bottom, rect1.right,
  797.                                     (item1Enabled) ? EnabledStr : DisabledStr);
  798.                         
  799.                         fprintf (stderr, DRectStateStr, string, rect2.top, rect2.left,
  800.                                     rect2.bottom, rect2.right,
  801.                                     (item2Enabled) ? EnabledStr : DisabledStr);
  802.                     }
  803.                     
  804.                     pData1 += sizeof (Item2Data) + (*(Item2Data*) pData1).what - sizeof (short);
  805.                     pData2 += sizeof (Item2Data) + (*(Item2Data*) pData2).what - sizeof (short);
  806.                     break;
  807.             }
  808.             
  809.             if ((long) pData1 & 1)
  810.                 pData1 ++;    // word aligned
  811.             
  812.             if ((long) pData2 & 1)
  813.                 pData2 ++;    // word aligned
  814.             
  815.             item ++;
  816.             item1Count --;
  817.             item2Count --;
  818.         }
  819.     }
  820.     
  821.     ReleaseResource (res1H);
  822.     ReleaseResource (res2H);
  823.     
  824. } // CompareDITLItems
  825.  
  826. //---------------------------------------------------------------------------------------------
  827. //    WriteDITLTypeIDItemStr:
  828. //---------------------------------------------------------------------------------------------
  829.  
  830. static void WriteDITLTypeIDItemStr (char* resTypeStr, ResID resID, short item,
  831.                                                 Boolean& headerWritten, Boolean& idWritten) {
  832.     
  833.     if (! headerWritten) {
  834.         fprintf (stderr, BadDItems);
  835.         headerWritten = TRUE;
  836.         gFilesMatch = FALSE;
  837.     }
  838.     
  839.     if (! idWritten) {
  840.         fprintf (stderr, TypeIDStr, resTypeStr, resID);
  841.         idWritten = TRUE;
  842.     }
  843.     
  844.     fprintf (stderr, ItemStr, item);
  845.     
  846. } // WriteDITLTypeIDItemStr
  847.  
  848. //---------------------------------------------------------------------------------------------
  849. //    CompareMenus: Compares number of items in 'CMNU' & 'MENU' resources with equal IDs.
  850. //---------------------------------------------------------------------------------------------
  851.  
  852. static void CompareMenus (short ref1Num, short ref2Num,
  853.                                     ResType resType, ResID resID, char* resTypeStr,
  854.                                     Boolean& headerWritten, short firstFile) {
  855.     
  856.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  857.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  858.     
  859.     if (res1H && res2H) {
  860.         short item1Count = RCCountMenuItems (res1H, resType);
  861.         short item2Count = RCCountMenuItems (res2H, resType);
  862.         
  863.         if (item1Count > item2Count) {
  864.             if (! headerWritten) {
  865.                 fprintf (stderr, (resType == 'MENU') ? ExtraMItems : ExtraCMItems,
  866.                             (firstFile == 1) ? File1Str : File2Str);
  867.                 headerWritten = TRUE;
  868.                 gFilesMatch = FALSE;
  869.             }
  870.             
  871.             fprintf (stderr, TypeIDExtraIStr, resTypeStr, resID, item1Count - item2Count);
  872.         }
  873.     }
  874.     
  875.     ReleaseResource (res1H);
  876.     ReleaseResource (res2H);
  877.     
  878. } // CompareMenus
  879.  
  880. //---------------------------------------------------------------------------------------------
  881. //    CompareMenuItems: Compares corresponding menu items.
  882. //---------------------------------------------------------------------------------------------
  883.  
  884. static void CompareMenuItems (short ref1Num, short ref2Num,
  885.                                         ResType resType, ResID resID, char* resTypeStr,
  886.                                         Boolean& headerWritten, short /*firstFile*/) {
  887.     
  888.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  889.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  890.     
  891.     if (res1H && res2H) {
  892.         HLock (res1H);
  893.         HLock (res2H);
  894.         
  895.         short item = 0;
  896.         Boolean idWritten = FALSE;
  897.         
  898.         MenuInfo& menu1Info = *(MenuInfo*) *res1H;
  899.         MenuInfo& menu2Info = *(MenuInfo*) *res2H;
  900.         
  901.         // Menu header is compared first
  902.         if ((menu1Info.menuID != menu2Info.menuID)
  903.         || (*(short*) &menu1Info.menuProc != *(short*) &menu2Info.menuProc)
  904.         || (menu1Info.enableFlags != menu2Info.enableFlags)) {
  905.             if (! headerWritten) {
  906.                 fprintf (stderr, (resType == 'MENU') ? BadMItems : BadCMItems);
  907.                 headerWritten = TRUE;
  908.                 gFilesMatch = FALSE;
  909.             }
  910.             
  911.             fprintf (stderr, TypeIDStr, resTypeStr, resID);
  912.             idWritten = TRUE;
  913.             
  914.             fprintf (stderr, HeaderStr);
  915.             fprintf (stderr, MenuHeaderStr, menu1Info.menuID, *(short*) &menu1Info.menuProc,
  916.                         menu1Info.enableFlags);
  917.             fprintf (stderr, MenuHeaderStr, menu2Info.menuID, *(short*) &menu2Info.menuProc,
  918.                         menu2Info.enableFlags);
  919.         }
  920.         
  921.         Ptr str1 = (Ptr) menu1Info.menuData;
  922.         Ptr str2 = (Ptr) menu2Info.menuData;
  923.         
  924.         do {
  925.             RotateCursor (++ gCursorCounter);
  926.             char icon1 = 0;
  927.             char icon2 = 0;
  928.             char key1 = 0;
  929.             char key2 = 0;
  930.             char mark1 = 0;
  931.             char mark2 = 0;
  932.             char style1 = 0;
  933.             char style2 = 0;
  934.             long command1Number = 0;
  935.             long command2Number = 0;
  936.             
  937.             if (item != 0) {
  938.                 Ptr pData = str1 + (unsigned char) *str1 + 1;
  939.                 icon1 = *pData ++;
  940.                 key1 = *pData ++;
  941.                 mark1 = *pData ++;
  942.                 style1 = (*pData ++) & 0x7F;
  943.                 
  944.                 if ((long) pData & 1)
  945.                     pData ++;        // word aligned
  946.                 
  947.                 if (resType == 'CMNU')
  948.                     command1Number = *(long*) pData;
  949.                 
  950.                 pData = str2 + (unsigned char) *str2 + 1;
  951.                 icon2 = *pData ++;
  952.                 key2 = *pData ++;
  953.                 mark2 = *pData ++;
  954.                 style2 = (*pData ++) & 0x7F;
  955.                 
  956.                 if ((long) pData & 1)
  957.                     pData ++;        // word aligned
  958.                 
  959.                 if (resType == 'CMNU')
  960.                     command2Number = *(long*) pData;
  961.             }
  962.             
  963.             Boolean attrsDontMatch = ((icon1 != icon2) || (key1 != key2)
  964.                                                 || (mark1 != mark2) || (style1 != style2));
  965.             Boolean cmdsDontMatch = (command1Number != command2Number);
  966.             Boolean stringsDontMatch = ((*str1 != *str2)
  967.                                                  || (memcmp (str1, str2, (unsigned char) *str1 + 1)));
  968.             
  969.             if ((gMenuStrings && stringsDontMatch)
  970.             || (cmdsDontMatch || attrsDontMatch)) {
  971.                 if (! headerWritten) {
  972.                     fprintf (stderr, (resType == 'MENU') ? BadMItems : BadCMItems);
  973.                     headerWritten = TRUE;
  974.                     gFilesMatch = FALSE;
  975.                 }
  976.                 
  977.                 if (! idWritten) {
  978.                     fprintf (stderr, TypeIDStr, resTypeStr, resID);
  979.                     idWritten = TRUE;
  980.                 }
  981.                 
  982.                 if (item == 0)
  983.                     fprintf (stderr, TitleStr);
  984.                 else
  985.                     fprintf (stderr, ItemStr, item);
  986.                 
  987.                 Str255 string;
  988.                 if (gMenuStrings)
  989.                     BlockMove (str1, string, (unsigned char) *str1 + 1);
  990.                 else
  991.                     string [0] = 0;
  992.                 p2cstr (string);
  993.                 
  994.                 if (cmdsDontMatch || attrsDontMatch) {
  995.                     if (! cmdsDontMatch)
  996.                         fprintf (stderr, MenuAttrsStr, string, icon1, key1, mark1, style1);
  997.                     else if (! attrsDontMatch)
  998.                         fprintf (stderr, MenuCmdStr, string, command1Number);
  999.                     else
  1000.                         fprintf (stderr, MenuCmdAttrsStr, string, command1Number,
  1001.                                     icon1, key1, mark1, style1);
  1002.                 }
  1003.                 else
  1004.                     fprintf (stderr, StringStr, string);
  1005.                 
  1006.                 if (gMenuStrings)
  1007.                     BlockMove (str2, string, (unsigned char) *str2 + 1);
  1008.                 else
  1009.                     string [0] = 0;
  1010.                 p2cstr (string);
  1011.                 
  1012.                 if (cmdsDontMatch || attrsDontMatch) {
  1013.                     if (! cmdsDontMatch)
  1014.                         fprintf (stderr, MenuAttrsStr, string, icon2, key2, mark2, style2);
  1015.                     else if (! attrsDontMatch)
  1016.                         fprintf (stderr, MenuCmdStr, string, command2Number);
  1017.                     else
  1018.                         fprintf (stderr, MenuCmdAttrsStr, string, command2Number,
  1019.                                     icon2, key2, mark2, style2);
  1020.                 }
  1021.                 else
  1022.                     fprintf (stderr, StringStr, string);
  1023.             }
  1024.             
  1025.             str1 += (unsigned char) *str1 + 1;
  1026.             str2 += (unsigned char) *str2 + 1;
  1027.             
  1028.             if (item != 0) {
  1029.                 // Note that there are four bytes of data after the item string for all menus
  1030.                 str1 += 4;
  1031.                 str2 += 4;
  1032.                 
  1033.                 if (resType == 'CMNU') {
  1034.                     if ((long) str1 & 1)
  1035.                         str1 ++;        // word aligned
  1036.                     str1 += 4;        // skip command number
  1037.                     
  1038.                     if ((long) str2 & 1)
  1039.                         str2 ++;        // word aligned
  1040.                     str2 += 4;        // skip command number
  1041.                 }
  1042.             }
  1043.             
  1044.             item ++;
  1045.             
  1046.         } while ((*str1 != 0) && (*str2 != 0));
  1047.     }
  1048.     
  1049.     ReleaseResource (res1H);
  1050.     ReleaseResource (res2H);
  1051.     
  1052. } // CompareMenuItems
  1053.  
  1054. //---------------------------------------------------------------------------------------------
  1055. //    CompareStringLists: Compares number of strings in 'STR#' resources with equal IDs.
  1056. //---------------------------------------------------------------------------------------------
  1057.  
  1058. static void CompareStringLists (short ref1Num, short ref2Num,
  1059.                                             ResType /*resType*/, ResID resID, char* resTypeStr,
  1060.                                             Boolean& headerWritten, short firstFile) {
  1061.     
  1062.     Handle res1H = GetTheResource (ref1Num, 'STR#', resID);
  1063.     Handle res2H = GetTheResource (ref2Num, 'STR#', resID);
  1064.     
  1065.     if (res1H && res2H) {
  1066.         short str1Count = *(short*) *res1H;
  1067.         short str2Count = *(short*) *res2H;
  1068.         
  1069.         if (str1Count > str2Count) {
  1070.             if (! headerWritten) {
  1071.                 fprintf (stderr, ExtraStrings, (firstFile == 1) ? File1Str : File2Str);
  1072.                 headerWritten = TRUE;
  1073.                 gFilesMatch = FALSE;
  1074.             }
  1075.             
  1076.             fprintf (stderr, TypeIDExtraSStr, resTypeStr, resID, str1Count - str2Count);
  1077.         }
  1078.     }
  1079.     
  1080.     ReleaseResource (res1H);
  1081.     ReleaseResource (res2H);
  1082.     
  1083. } // CompareStringLists
  1084.  
  1085. //---------------------------------------------------------------------------------------------
  1086. //    CompareStrings: Compares corresponding 'STR#' & 'STR ' strings.
  1087. //---------------------------------------------------------------------------------------------
  1088.  
  1089. static void CompareStrings (short ref1Num, short ref2Num,
  1090.                                         ResType resType, ResID resID, char* resTypeStr,
  1091.                                         Boolean& headerWritten, short /*firstFile*/) {
  1092.     
  1093.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  1094.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  1095.     
  1096.     if (res1H && res2H) {
  1097.         HLock (res1H);
  1098.         HLock (res2H);
  1099.         
  1100.         short strCount = 1;
  1101.         Ptr str1 = *res1H;
  1102.         Ptr str2 = *res2H;
  1103.         
  1104.         if (resType == 'STR#') {
  1105.             short res1StrCount = *(short*) str1;
  1106.             short res2StrCount = *(short*) str2;
  1107.             strCount = (res1StrCount <= res2StrCount) ? res1StrCount : res2StrCount;
  1108.             
  1109.             str1 += sizeof (short);
  1110.             str2 += sizeof (short);
  1111.         }
  1112.         
  1113.         Boolean idWritten = FALSE;
  1114.         
  1115.         for (short item = 1; item <= strCount; item ++) {
  1116.             RotateCursor (++ gCursorCounter);
  1117.             
  1118.             if ((*str1 != *str2)
  1119.             || (memcmp (str1, str2, (unsigned char) *str1 + 1))) {
  1120.                 if (! headerWritten) {
  1121.                     fprintf (stderr, (resType == 'STR#') ? BadLStrings : BadStrings);
  1122.                     headerWritten = TRUE;
  1123.                     gFilesMatch = FALSE;
  1124.                 }
  1125.                 
  1126.                 if (resType == 'STR#') {
  1127.                     if (! idWritten) {
  1128.                         fprintf (stderr, TypeIDStr, resTypeStr, resID);
  1129.                         idWritten = TRUE;
  1130.                     }
  1131.                     
  1132.                     fprintf (stderr, ItemStr, item);
  1133.                 }
  1134.                 else
  1135.                     fprintf (stderr, TypeIDStr, resTypeStr, resID);
  1136.                 
  1137.                 Str255 string;
  1138.                 BlockMove (str1, string, (unsigned char) *str1 + 1);
  1139.                 p2cstr (string);
  1140.                 fprintf (stderr, StringStr, string);
  1141.                 
  1142.                 BlockMove (str2, string, (unsigned char) *str2 + 1);
  1143.                 p2cstr (string);
  1144.                 fprintf (stderr, StringStr, string);
  1145.             }
  1146.             
  1147.             str1 += (unsigned char) *str1 + 1;
  1148.             str2 += (unsigned char) *str2 + 1;
  1149.         }
  1150.     }
  1151.     
  1152.     ReleaseResource (res1H);
  1153.     ReleaseResource (res2H);
  1154.     
  1155. } // CompareStrings
  1156.  
  1157. //---------------------------------------------------------------------------------------------
  1158. //    CompareViews: Compares 'View' resources with equal IDs.
  1159. //---------------------------------------------------------------------------------------------
  1160.  
  1161. static void CompareViews (short ref1Num, short ref2Num,
  1162.                                     ResType resType, ResID resID, char* resTypeStr,
  1163.                                     Boolean& headerWritten, short firstFile) {
  1164.     
  1165.     // Handled as generic resources for now
  1166.     CompareGeneric (ref1Num, ref2Num, resType, resID, resTypeStr,
  1167.                             headerWritten, firstFile);
  1168.     
  1169. } // CompareViews
  1170.  
  1171. //---------------------------------------------------------------------------------------------
  1172. //    CompareGeneric: Compares generic resources with equal IDs.
  1173. //---------------------------------------------------------------------------------------------
  1174.  
  1175. static void CompareGeneric (short ref1Num, short ref2Num,
  1176.                                         ResType resType, ResID resID, char* resTypeStr,
  1177.                                         Boolean& headerWritten, short /*firstFile*/) {
  1178.     
  1179.     Handle res1H = GetTheResource (ref1Num, resType, resID);
  1180.     Handle res2H = GetTheResource (ref2Num, resType, resID);
  1181.     
  1182.     if (res1H && res2H) {
  1183.         long res1HSize = GetHandleSize (res1H);
  1184.         
  1185.         if ((res1HSize != GetHandleSize (res2H))
  1186.         || (memcmp (*res1H, *res2H, (unsigned int) res1HSize))) {
  1187.             if (! headerWritten) {
  1188.                 if (resType == 'View')
  1189.                     fprintf (stderr, BadViews);
  1190.                 else
  1191.                     fprintf (stderr, BadResources);
  1192.                 
  1193.                 headerWritten = TRUE;
  1194.                 gFilesMatch = FALSE;
  1195.             }
  1196.             
  1197.             fprintf (stderr, TypeIDStr, resTypeStr, resID);
  1198.         }
  1199.     }
  1200.     
  1201.     ReleaseResource (res1H);
  1202.     ReleaseResource (res2H);
  1203.     
  1204. } // CompareGeneric
  1205.  
  1206. //---------------------------------------------------------------------------------------------
  1207. // IterateResIDs: Iterates thru all resIDs calling <doCompare> function for equal resIDs.
  1208. //---------------------------------------------------------------------------------------------
  1209.  
  1210. static void IterateResIDs (short ref1Num, short ref2Num, ResType resType,
  1211.                                     ResID** res1TableH, ResID** res2TableH,
  1212.                                     short res1Count, short res2Count, short firstFile,
  1213.                                     DoCompare doCompare, Boolean& headerWritten) {
  1214.     
  1215.     char resTypeStr [6];
  1216.     ResType2str (resTypeStr, resType);
  1217.     
  1218.     short index1 = 0;
  1219.     short index2 = 0;
  1220.     
  1221.     while ((index1 < res1Count) && (index2 < res2Count)) {
  1222.         RotateCursor (++ gCursorCounter);
  1223.         ResID resID = (*res1TableH) [index1];
  1224.         
  1225.         if (resID < (*res2TableH) [index2]) {
  1226.             // Extra ID in table1
  1227.             index1 ++;
  1228.         }
  1229.         else if (resID > (*res2TableH) [index2]) {
  1230.             // Extra ID in table2
  1231.             index2 ++;
  1232.         }
  1233.         else {
  1234.             doCompare (ref1Num, ref2Num, resType, resID, resTypeStr, headerWritten, firstFile);
  1235.             index1 ++;
  1236.             index2 ++;
  1237.         }
  1238.     }
  1239.     
  1240.     if ((firstFile != 0) && headerWritten) {
  1241.         fprintf (stderr, "\n");
  1242.         headerWritten = FALSE;
  1243.     }
  1244.     
  1245. } // IterateResIDs
  1246.  
  1247. //---------------------------------------------------------------------------------------------
  1248. //    BuildTypesTable: Builds ordered table of resource types.
  1249. //---------------------------------------------------------------------------------------------
  1250.  
  1251. static ResType** BuildTypesTable (short refNum) {
  1252.     
  1253.     short curRefNum = SetResourceFile (refNum);
  1254.     short typesCount = Count1Types ();
  1255.     ResType** typesTableH = (ResType**) NewHandle (typesCount * sizeof (ResType));
  1256.     
  1257.     for (short typeIndex = 1; typeIndex <= typesCount; typeIndex ++) {
  1258.         ResType resType;
  1259.         Get1IndType (&resType, typeIndex);
  1260.         
  1261.         ResType* pTypes = *typesTableH;
  1262.         for (short i = 1; i < typeIndex; i ++) {
  1263.             if (resType < *pTypes) {
  1264.                 BlockMove (pTypes, pTypes + 1, (typeIndex - i) * sizeof (ResType));
  1265.                 break;
  1266.             }
  1267.             
  1268.             pTypes ++;
  1269.         }
  1270.         
  1271.         *pTypes = resType;
  1272.     }
  1273.     
  1274.     UseResFile (curRefNum);
  1275.     return (typesTableH);
  1276.     
  1277. } // BuildTypesTable
  1278.  
  1279. //---------------------------------------------------------------------------------------------
  1280. //    BuildResIDsTable: Builds ordered table of resource IDs.
  1281. //---------------------------------------------------------------------------------------------
  1282.  
  1283. static ResID** BuildResIDsTable (short refNum, ResType resType) {
  1284.     
  1285.     short curRefNum = SetResourceFile (refNum);
  1286.     short resCount = Count1Resources (resType);
  1287.     ResID** resTableH = (ResID**) NewHandle (resCount * sizeof (ResID));
  1288.     
  1289.     for (short resIndex = 1; resIndex <= resCount; resIndex ++) {
  1290.         ResType dontCare;
  1291.         Str255 resName;
  1292.         short resID;
  1293.         
  1294.         Handle resH = Get1IndResource (resType, resIndex);
  1295.         GetResInfo (resH, &resID, &dontCare, resName);
  1296.         
  1297.         ResID* pIDs = *resTableH;
  1298.         for (short i = 1; i < resIndex; i ++) {
  1299.             if (resID < *pIDs) {
  1300.                 BlockMove (pIDs, pIDs + 1, (resIndex - i) * sizeof (ResID));
  1301.                 break;
  1302.             }
  1303.             
  1304.             pIDs ++;
  1305.         }
  1306.         
  1307.         *pIDs = resID;
  1308.     }
  1309.     
  1310.     UseResFile (curRefNum);
  1311.     return (resTableH);
  1312.     
  1313. } // BuildResIDsTable
  1314.  
  1315. //---------------------------------------------------------------------------------------------
  1316. // BuildResIDsTables:
  1317. //---------------------------------------------------------------------------------------------
  1318.  
  1319. static void BuildResIDsTables (short ref1Num, short ref2Num, ResType resType,
  1320.                                             ResID**& res1TableH, ResID**& res2TableH,
  1321.                                             short& res1Count, short& res2Count) {
  1322.     
  1323.     res1TableH = BuildResIDsTable (ref1Num, resType);
  1324.     res2TableH = BuildResIDsTable (ref2Num, resType);
  1325.     
  1326.     res1Count = (short) GetHandleSize ((Handle) res1TableH) / sizeof (short);
  1327.     res2Count = (short) GetHandleSize ((Handle) res2TableH) / sizeof (short);
  1328.     
  1329. } // BuildResIDsTables
  1330.  
  1331. //---------------------------------------------------------------------------------------------
  1332. // GetTheResource: Gets a resource from the appropriate resource file.
  1333. //---------------------------------------------------------------------------------------------
  1334.  
  1335. static Handle GetTheResource (short refNum, ResType resType, ResID resID) {
  1336.     
  1337.     short curRefNum = SetResourceFile (refNum);
  1338.     Handle resH = Get1Resource (resType, resID);
  1339.     
  1340.     UseResFile (curRefNum);
  1341.     return (resH);
  1342.     
  1343. } // GetTheResource
  1344.  
  1345. //---------------------------------------------------------------------------------------------
  1346. // SetResourceFile: Sets the resource file to be used.
  1347. //---------------------------------------------------------------------------------------------
  1348.  
  1349. static short SetResourceFile (short refNum) {
  1350.     
  1351.     short curRefNum = CurResFile ();
  1352.     if (curRefNum != refNum)
  1353.         UseResFile (refNum);
  1354.     
  1355.     return (curRefNum);
  1356.     
  1357. } // SetResourceFile
  1358.  
  1359. //---------------------------------------------------------------------------------------------
  1360. // ResType2str: Returns in resTypeStr a resType in a form of a C string.
  1361. //---------------------------------------------------------------------------------------------
  1362.  
  1363. static void ResType2str (char* resTypeStr, ResType resType) {
  1364.     
  1365.     *(ResType*) resTypeStr = resType;
  1366.     resTypeStr [sizeof (resType)] = 0;
  1367.     
  1368. } // ResType2str
  1369.  
  1370. //---------------------------------------------------------------------------------------------
  1371. // RCCountMenuItems: Returns number of items in specified 'MENU' or 'CMNU'.
  1372. //---------------------------------------------------------------------------------------------
  1373.  
  1374. static short RCCountMenuItems (Handle menuH, ResType resType) {
  1375.     
  1376.     Ptr pData = (Ptr) (*(MenuInfo*) *menuH).menuData;
  1377.     
  1378.     // Skip the menu title
  1379.     pData += (unsigned char) *pData + 1;
  1380.     
  1381.     short itemCount = 0;
  1382.     while (*pData != 0) {
  1383.         // Note that there are four bytes of data after the item string for all menus
  1384.         pData += (unsigned char) *pData + 1 + 4;
  1385.         
  1386.         if (resType == 'CMNU') {
  1387.             if ((long) pData & 1)
  1388.                 pData ++;        // word aligned
  1389.             
  1390.             pData += 4;            // skip command number
  1391.         }
  1392.         
  1393.         itemCount ++;
  1394.     }
  1395.     
  1396.     return (itemCount);
  1397.     
  1398. } // RCCountMenuItems
  1399.