Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
6.9 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. rcunicod.c
  5. Abstract:
  6. Routines added to rcpp to support 16-bit unicode file parsing.
  7. Note that as of Aug 91, rcpp will not fully transfer the unicode
  8. characters but only the string constants are guaranteed to be passed
  9. cleanly.
  10. Author:
  11. David J. Marsyla (t-davema) 25-Aug-1991
  12. Revision History:
  13. --*/
  14. #include <stdio.h>
  15. #include <ctype.h>
  16. #include <process.h>
  17. #include "windows.h"
  18. #include "rcunicod.h"
  19. INT
  20. DetermineFileType (
  21. IN FILE *fpInputFile
  22. )
  23. /*++
  24. Routine Description:
  25. This function is used to determine what type of file is being read.
  26. Note that it assumes that the first few bytes of the given file contain
  27. mostly ascii characters. This routine was originally intended for use
  28. on .rc files and include files.
  29. Note, the file is returned to it's proper position after function.
  30. Arguments:
  31. fpInputFile - File pointer to file we are checking, must be
  32. open with read permissions.
  33. Return Value:
  34. DFT_FILE_IS_UNKNOWN - It was impossible to determine what type of file
  35. we were checking. This usually happens when EOF
  36. is unexpectedly reached.
  37. DFT_FILE_IS_8_BIT - File was determined to be in standard 8-bit
  38. format.
  39. DFT_FILE_IS_16_BIT - File was determined to be a 16 bit unicode file
  40. which can be directly read into a WCHAR array.
  41. DFT_FILE_IS_16_BIT_REV - File was determined to be a 16 bit unicode file
  42. which has it's bytes reversed in order.
  43. --*/
  44. {
  45. CHAR rgchTestBytes [DFT_TEST_SIZE << 2]; // Storage for test data.
  46. INT cNumberBytesTested = 0; // Test information.
  47. INT cNumberOddZerosFound = 0;
  48. INT cNumberEvenZerosFound = 0;
  49. INT cNumberAsciiFound = 0;
  50. INT cCountRead; // Temp storage for count read.
  51. LONG lStartFilePos; // Storage for file position.
  52. INT fSysEndianType; // System endian type.
  53. INT fFileType = DFT_FILE_IS_UNKNOWN;// File type, when found.
  54. fSysEndianType = DetermineSysEndianType ();
  55. //
  56. // Store position so we can get back to it.
  57. //
  58. lStartFilePos = ftell (fpInputFile);
  59. //
  60. // Make sure we start on an even byte to simplify routines.
  61. //
  62. if (lStartFilePos % 2) {
  63. fgetc (fpInputFile);
  64. }
  65. do {
  66. INT wT;
  67. //
  68. // Read in the first test segment.
  69. //
  70. cCountRead = fread (rgchTestBytes, sizeof (CHAR), DFT_TEST_SIZE << 2,
  71. fpInputFile);
  72. //
  73. // Determine results and add to totals.
  74. //
  75. for (wT = 0; wT < cCountRead; wT++) {
  76. if (rgchTestBytes [wT] == 0) {
  77. if (wT % 2) {
  78. cNumberOddZerosFound++;
  79. } else {
  80. cNumberEvenZerosFound++;
  81. }
  82. }
  83. if (isprint (rgchTestBytes [wT]) ||
  84. rgchTestBytes[wT] == '\t' ||
  85. rgchTestBytes[wT] == '\n' ||
  86. rgchTestBytes[wT] == '\r' ) {
  87. cNumberAsciiFound++;
  88. }
  89. }
  90. cNumberBytesTested += cCountRead;
  91. //
  92. // Check if we have a definite pattern.
  93. //
  94. {
  95. INT cMajorityTested; // 80% of the bytes tested.
  96. cMajorityTested = cNumberBytesTested << 2;
  97. cMajorityTested /= 5;
  98. if (cNumberAsciiFound > cMajorityTested) {
  99. fFileType = DFT_FILE_IS_8_BIT;
  100. } else if (cNumberOddZerosFound > (cMajorityTested >> 1)) {
  101. //
  102. // File type was determined to be little endian.
  103. // If system is also little endian, byte order is correct.
  104. //
  105. fFileType = (fSysEndianType == DSE_SYS_LITTLE_ENDIAN) ?
  106. DFT_FILE_IS_16_BIT : DFT_FILE_IS_16_BIT_REV;
  107. } else if (cNumberEvenZerosFound > (cMajorityTested >> 1)) {
  108. //
  109. // File type was determined to be big endian.
  110. // If system is also big endian, byte order is correct.
  111. //
  112. fFileType = (fSysEndianType == DSE_SYS_LITTLE_ENDIAN) ?
  113. DFT_FILE_IS_16_BIT_REV : DFT_FILE_IS_16_BIT;
  114. }
  115. }
  116. } while (cCountRead == (DFT_TEST_SIZE << 2) &&
  117. fFileType == DFT_FILE_IS_UNKNOWN);
  118. //
  119. // Return to starting file position. (usually beginning)
  120. //
  121. if (fseek (fpInputFile, lStartFilePos, SEEK_SET) == -1)
  122. fFileType = DFT_FILE_IS_UNKNOWN;
  123. return (fFileType);
  124. }
  125. INT
  126. DetermineSysEndianType (
  127. VOID
  128. )
  129. /*++
  130. Routine Description:
  131. This function is used to determine how the current system stores its
  132. integers in memory.
  133. For those of us who are confused by little endian and big endian formats,
  134. here is a breif recap.
  135. Little Endian: (This is used on Intel 80x86 chips. The MIPS RS4000 chip
  136. is switchable, but will run in little endian format for NT.)
  137. This is where the high order bytes of a short or long are stored higher
  138. in memory. For example the number 0x80402010 is stored as follows.
  139. Address: Value:
  140. 00 10
  141. 01 20
  142. 02 40
  143. 03 80
  144. This looks backwards when memory is dumped in order: 10 20 40 80
  145. Big Endian: (This is not currently used on any NT systems but hey, this
  146. is supposed to be portable!!)
  147. This is where the high order bytes of a short or long are stored lower
  148. in memory. For example the number 0x80402010 is stored as follows.
  149. Address: Value:
  150. 00 80
  151. 01 40
  152. 02 20
  153. 03 10
  154. This looks correct when memory is dumped in order: 80 40 20 10
  155. Arguments:
  156. None.
  157. Return Value:
  158. DSE_SYS_LITTLE_ENDIAN - The system stores integers in little endian
  159. format. (this is 80x86 default).
  160. DSE_SYS_BIG_ENDIAN - The system stores integers in big endian format.
  161. --*/
  162. {
  163. INT nCheckInteger;
  164. CHAR rgchTestBytes [sizeof (INT)];
  165. //
  166. // Clear the test bytes to zero.
  167. //
  168. *((INT *)rgchTestBytes) = 0;
  169. //
  170. // Set first to some value.
  171. //
  172. rgchTestBytes [0] = (UCHAR)0xFF;
  173. //
  174. // Map it to an integer.
  175. //
  176. nCheckInteger = *((INT *)rgchTestBytes);
  177. //
  178. // See if value was stored in low order of integer.
  179. // If so then system is little endian.
  180. //
  181. if (nCheckInteger == 0xFF) {
  182. return (DSE_SYS_LITTLE_ENDIAN);
  183. } else {
  184. return (DSE_SYS_LITTLE_ENDIAN);
  185. }
  186. }