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.

369 lines
10 KiB

  1. /******************************************************************\
  2. * Microsoft Windows NT *
  3. * Copyright(c) Microsoft Corp., 1992 *
  4. \******************************************************************/
  5. /*++
  6. Filename: COMPRESS.C
  7. Description: Contains procedures to compress and decompress phone
  8. numbers stored in the user parms field in the UAS.
  9. Note:
  10. The routines were originally developed to operate on
  11. Multi-byte strings. A Unicode wrapper using wcstombs()
  12. and mbstowcs() functions was written around the original
  13. functions and so you see the malloc() and free() usage
  14. as well. Both these routines should be rewritten to be
  15. native Unicode routines when time permits.
  16. History:
  17. July 1,1991. NarenG Created original version.
  18. July 6,1992. RamC Ported to NT - removed several
  19. header file includes and changed
  20. memsetf to memset & strchrf to strchr
  21. June 4,1996. RamC Allow any alphanumeric character to be
  22. specified in the Callback phone number.
  23. --*/
  24. #include <windows.h>
  25. #include <string.h>
  26. #include <lm.h>
  27. #include <stdlib.h>
  28. #include <memory.h>
  29. #include <mprapi.h>
  30. #include <usrparms.h> // UP_LEN_DIAL
  31. #include <raserror.h>
  32. #include <rasman.h>
  33. #include <rasppp.h>
  34. #include <compress.h>
  35. // some convenient defines
  36. static CHAR * CompressMap = "() tTpPwW,-@*#";
  37. #define UNPACKED_DIGIT 100
  38. #define COMPRESS_MAP_BEGIN 110
  39. #define COMPRESS_MAP_END (COMPRESS_MAP_BEGIN + strlen(CompressMap))
  40. #define UNPACKED_OTHER (COMPRESS_MAP_END + 1)
  41. USHORT
  42. WINAPI
  43. CompressPhoneNumber(
  44. IN LPWSTR UncompNumber,
  45. OUT LPWSTR CompNumber
  46. )
  47. /*
  48. Routine Description:
  49. Will compress a phone number so that it may fit in the
  50. userparms field.
  51. Arguments
  52. UncompNumber - Pointer to the phone number that
  53. will be compressed.
  54. CompNumber - Pointer to a buffer that is at least as long
  55. as the Uncompressed number. On return
  56. this will contain the compressed
  57. phone number.
  58. Return Value:
  59. 0 if successful
  60. One of the following error codes otherwise:
  61. ERROR_BAD_CALLBACK_NUMBER - failure, if the Uncompressed number
  62. has invalid chars.
  63. ERROR_BAD_LENGTH - failure, if the compressed
  64. phone number will not fit
  65. in the userparms field.
  66. Algortithm Used:
  67. An attempt is made to fit the given string in half the number of
  68. bytes by packing two adjacent numbers (in the phone number) in
  69. one byte. For example if the phone number is "8611824", instead
  70. of storing it in 8 bytes (including the trailing NULL), it is
  71. stored in 4 bytes. '0' is special case because it cannot be a
  72. byte by itself - will be interpreted as the terminating NULL.
  73. So, if two zeros appear next to each other as in "96001234", the
  74. two zeros are stored as the value 100. Also the special characters
  75. which are allowed in the phone number string - "() tTpPwW,-@*#"
  76. are stored as 110 + the index position in the above string. So,
  77. the '(' character would be stored as 110 (110+0) and the letter
  78. 't' as 113 (110+3).
  79. */
  80. {
  81. CHAR * Uncompressed;
  82. CHAR * Compressed;
  83. CHAR * UncompressedPtr;
  84. CHAR * CompressedPtr;
  85. CHAR * CharPtr;
  86. USHORT Packed; // Indicates if the current byte is in the
  87. // process of being paired.
  88. if(!(Uncompressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
  89. return(ERROR_NOT_ENOUGH_MEMORY);
  90. }
  91. if(!(Compressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
  92. return(ERROR_NOT_ENOUGH_MEMORY);
  93. }
  94. CompressedPtr = Compressed;
  95. UncompressedPtr = Uncompressed;
  96. // convert unicode string to multi byte string for compression
  97. wcstombs(Uncompressed, UncompNumber, MAX_PHONE_NUMBER_LEN);
  98. for( Packed = 0; *Uncompressed; Uncompressed++ ) {
  99. switch( *Uncompressed ) {
  100. case '0':
  101. if ( Packed ){
  102. // Put zero as the second paired digit
  103. if ( *Compressed ) {
  104. *Compressed = (UCHAR)(*Compressed * 10);
  105. Compressed++;
  106. Packed = 0;
  107. }
  108. // We have a zero, we cant put a second zero or that
  109. // will be a null byte. So, we store the value
  110. // UNPACKED_DIGIT to fake this.
  111. else {
  112. *Compressed = UNPACKED_DIGIT;
  113. *(++Compressed) = 0;
  114. Packed = 1;
  115. }
  116. }
  117. else {
  118. *Compressed = 0;
  119. Packed = 1;
  120. }
  121. break;
  122. case '1':
  123. case '2':
  124. case '3':
  125. case '4':
  126. case '5':
  127. case '6':
  128. case '7':
  129. case '8':
  130. case '9':
  131. // If this is the second digit that is going to be
  132. // packed into one byte
  133. if ( Packed ) {
  134. *Compressed = (UCHAR)((*Compressed*10)+(*Uncompressed-'0'));
  135. // we need to special case number 32 which maps to a blank
  136. if(*Compressed == ' ' )
  137. *Compressed = COMPRESS_MAP_END;
  138. Compressed++;
  139. Packed = 0;
  140. }
  141. else {
  142. *Compressed += ( *Uncompressed - '0' );
  143. Packed = 1;
  144. }
  145. break;
  146. case '(':
  147. case ')':
  148. case ' ':
  149. case 't':
  150. case 'T':
  151. case 'p':
  152. case 'P':
  153. case 'w':
  154. case 'W':
  155. case ',':
  156. case '-':
  157. case '@':
  158. case '*':
  159. case '#':
  160. // if the byte was packed then we unpack it
  161. if ( Packed ) {
  162. *Compressed += UNPACKED_DIGIT;
  163. ++Compressed;
  164. Packed = 0;
  165. }
  166. if ((CharPtr=strchr(CompressMap, *Uncompressed)) == NULL) {
  167. free(UncompressedPtr);
  168. free(CompressedPtr);
  169. return( ERROR_BAD_CALLBACK_NUMBER );
  170. }
  171. *Compressed = (UCHAR)(COMPRESS_MAP_BEGIN+
  172. (UCHAR)(CharPtr-CompressMap));
  173. Compressed++;
  174. break;
  175. default:
  176. // if the chracter is none of the above specially recognized
  177. // characters then copy the value + UNPACKED_OTHER to make it
  178. // possible to decompress at the other end. [ 6/4/96 RamC ]
  179. if ( Packed) {
  180. *Compressed += UNPACKED_DIGIT;
  181. ++Compressed;
  182. Packed = 0;
  183. }
  184. *Compressed = *Uncompressed + UNPACKED_OTHER;
  185. Compressed++;
  186. }
  187. }
  188. free(UncompressedPtr);
  189. // If we are in the middle of packing something
  190. // then we unpack it
  191. if ( Packed )
  192. *Compressed += UNPACKED_DIGIT;
  193. // Check if it will fit in the userparms field or not
  194. if ( strlen( CompressedPtr ) > UP_LEN_DIAL ) {
  195. free(CompressedPtr);
  196. return( ERROR_BAD_LENGTH );
  197. }
  198. // convert to unicode string before returning
  199. mbstowcs(CompNumber, CompressedPtr, MAX_PHONE_NUMBER_LEN);
  200. free(CompressedPtr);
  201. return(0);
  202. }
  203. USHORT
  204. DecompressPhoneNumber(
  205. IN LPWSTR CompNumber,
  206. OUT LPWSTR DecompNumber
  207. )
  208. /*++
  209. Routine Description:
  210. Will decompress a phone number.
  211. Arguments:
  212. CompNumber - Pointer to a compressed phone number.
  213. DecompNumber - Pointer to a buffer that is large enough to
  214. hold the Decompressed number.
  215. Return Value:
  216. 0 on success
  217. ERROR_BAD_CALLBACK_NUMBER - failure, if the Compressed number
  218. contains unrecognizable chars.
  219. Algortithm Used:
  220. We just do the opposite of the algorithm used in CompressPhoneNumber.
  221. --*/
  222. {
  223. CHAR * Decompressed;
  224. CHAR * Compressed;
  225. CHAR * DecompressedPtr;
  226. CHAR * CompressedPtr;
  227. if(!(Decompressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
  228. return(ERROR_NOT_ENOUGH_MEMORY);
  229. }
  230. if(!(Compressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
  231. return(ERROR_NOT_ENOUGH_MEMORY);
  232. }
  233. DecompressedPtr = Decompressed;
  234. CompressedPtr = Compressed;
  235. // convert unicode string to multi byte string for decompression
  236. wcstombs(Compressed, CompNumber, MAX_PHONE_NUMBER_LEN+1);
  237. for(; *Compressed; Compressed++, Decompressed++ ) {
  238. // If this byte is packed then we unpack it
  239. if ( (UINT)*Compressed < UNPACKED_DIGIT ) {
  240. *Decompressed = (UCHAR)(((*Compressed) / 10) + '0' );
  241. *(++Decompressed) = (UCHAR)( ((*Compressed) % 10) + '0' );
  242. continue;
  243. }
  244. // we need to special case number 32 which maps to a blank
  245. if ( (UINT)*Compressed == COMPRESS_MAP_END ) {
  246. *Decompressed = (UCHAR) '3';
  247. *(++Decompressed) = (UCHAR)'2';
  248. continue;
  249. }
  250. // the number is an unpacked digit
  251. if ( (UINT)*Compressed < COMPRESS_MAP_BEGIN ) {
  252. *Decompressed = (UCHAR)((*Compressed -(UCHAR)UNPACKED_DIGIT ) +
  253. '0' );
  254. continue;
  255. }
  256. // Otherwise the byte was not packed
  257. if ( (UINT)*Compressed < UNPACKED_OTHER ) {
  258. *Decompressed = CompressMap[(*Compressed -
  259. (UCHAR)COMPRESS_MAP_BEGIN)];
  260. continue;
  261. }
  262. // otherwise the byte is an unpacked character [ 6/4/96 RamC ]
  263. *Decompressed = *Compressed - UNPACKED_OTHER;
  264. }
  265. // convert to unicode string before returning
  266. mbstowcs(DecompNumber, DecompressedPtr, MAX_PHONE_NUMBER_LEN+1);
  267. free(DecompressedPtr);
  268. free(CompressedPtr);
  269. return( 0 );
  270. }