370 lines
10 KiB
C
370 lines
10 KiB
C
/******************************************************************\
|
||
* Microsoft Windows NT *
|
||
* Copyright(c) Microsoft Corp., 1992 *
|
||
\******************************************************************/
|
||
|
||
/*++
|
||
|
||
Filename: COMPRESS.C
|
||
|
||
Description: Contains procedures to compress and decompress phone
|
||
numbers stored in the user parms field in the UAS.
|
||
|
||
Note:
|
||
The routines were originally developed to operate on
|
||
Multi-byte strings. A Unicode wrapper using wcstombs()
|
||
and mbstowcs() functions was written around the original
|
||
functions and so you see the malloc() and free() usage
|
||
as well. Both these routines should be rewritten to be
|
||
native Unicode routines when time permits.
|
||
|
||
History:
|
||
July 1,1991. NarenG Created original version.
|
||
July 6,1992. RamC Ported to NT - removed several
|
||
header file includes and changed
|
||
memsetf to memset & strchrf to strchr
|
||
June 4,1996. RamC Allow any alphanumeric character to be
|
||
specified in the Callback phone number.
|
||
--*/
|
||
|
||
#include <windows.h>
|
||
#include <string.h>
|
||
#include <lm.h>
|
||
#include <stdlib.h>
|
||
#include <memory.h>
|
||
#include <mprapi.h>
|
||
#include <usrparms.h> // UP_LEN_DIAL
|
||
#include <raserror.h>
|
||
#include <rasman.h>
|
||
#include <rasppp.h>
|
||
#include <compress.h>
|
||
|
||
// some convenient defines
|
||
|
||
static CHAR * CompressMap = "() tTpPwW,-@*#";
|
||
|
||
#define UNPACKED_DIGIT 100
|
||
#define COMPRESS_MAP_BEGIN 110
|
||
#define COMPRESS_MAP_END (COMPRESS_MAP_BEGIN + strlen(CompressMap))
|
||
#define UNPACKED_OTHER (COMPRESS_MAP_END + 1)
|
||
|
||
|
||
|
||
USHORT
|
||
WINAPI
|
||
CompressPhoneNumber(
|
||
IN LPWSTR UncompNumber,
|
||
OUT LPWSTR CompNumber
|
||
)
|
||
|
||
/*
|
||
|
||
Routine Description:
|
||
|
||
Will compress a phone number so that it may fit in the
|
||
userparms field.
|
||
|
||
|
||
Arguments
|
||
|
||
UncompNumber - Pointer to the phone number that
|
||
will be compressed.
|
||
|
||
CompNumber - Pointer to a buffer that is at least as long
|
||
as the Uncompressed number. On return
|
||
this will contain the compressed
|
||
phone number.
|
||
|
||
Return Value:
|
||
|
||
0 if successful
|
||
|
||
One of the following error codes otherwise:
|
||
|
||
ERROR_BAD_CALLBACK_NUMBER - failure, if the Uncompressed number
|
||
has invalid chars.
|
||
ERROR_BAD_LENGTH - failure, if the compressed
|
||
phone number will not fit
|
||
in the userparms field.
|
||
|
||
Algortithm Used:
|
||
|
||
An attempt is made to fit the given string in half the number of
|
||
bytes by packing two adjacent numbers (in the phone number) in
|
||
one byte. For example if the phone number is "8611824", instead
|
||
of storing it in 8 bytes (including the trailing NULL), it is
|
||
stored in 4 bytes. '0' is special case because it cannot be a
|
||
byte by itself - will be interpreted as the terminating NULL.
|
||
So, if two zeros appear next to each other as in "96001234", the
|
||
two zeros are stored as the value 100. Also the special characters
|
||
which are allowed in the phone number string - "() tTpPwW,-@*#"
|
||
are stored as 110 + the index position in the above string. So,
|
||
the '(' character would be stored as 110 (110+0) and the letter
|
||
't' as 113 (110+3).
|
||
*/
|
||
|
||
{
|
||
CHAR * Uncompressed;
|
||
CHAR * Compressed;
|
||
CHAR * UncompressedPtr;
|
||
CHAR * CompressedPtr;
|
||
CHAR * CharPtr;
|
||
USHORT Packed; // Indicates if the current byte is in the
|
||
// process of being paired.
|
||
|
||
if(!(Uncompressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
if(!(Compressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
CompressedPtr = Compressed;
|
||
UncompressedPtr = Uncompressed;
|
||
|
||
// convert unicode string to multi byte string for compression
|
||
|
||
wcstombs(Uncompressed, UncompNumber, MAX_PHONE_NUMBER_LEN);
|
||
|
||
|
||
for( Packed = 0; *Uncompressed; Uncompressed++ ) {
|
||
|
||
switch( *Uncompressed ) {
|
||
|
||
case '0':
|
||
|
||
if ( Packed ){
|
||
|
||
// Put zero as the second paired digit
|
||
|
||
if ( *Compressed ) {
|
||
*Compressed = (UCHAR)(*Compressed * 10);
|
||
Compressed++;
|
||
Packed = 0;
|
||
}
|
||
|
||
// We have a zero, we cant put a second zero or that
|
||
// will be a null byte. So, we store the value
|
||
// UNPACKED_DIGIT to fake this.
|
||
|
||
else {
|
||
|
||
*Compressed = UNPACKED_DIGIT;
|
||
*(++Compressed) = 0;
|
||
Packed = 1;
|
||
}
|
||
}
|
||
else {
|
||
*Compressed = 0;
|
||
Packed = 1;
|
||
}
|
||
|
||
break;
|
||
|
||
case '1':
|
||
case '2':
|
||
case '3':
|
||
case '4':
|
||
case '5':
|
||
case '6':
|
||
case '7':
|
||
case '8':
|
||
case '9':
|
||
|
||
// If this is the second digit that is going to be
|
||
// packed into one byte
|
||
|
||
if ( Packed ) {
|
||
*Compressed = (UCHAR)((*Compressed*10)+(*Uncompressed-'0'));
|
||
// we need to special case number 32 which maps to a blank
|
||
if(*Compressed == ' ' )
|
||
*Compressed = COMPRESS_MAP_END;
|
||
Compressed++;
|
||
Packed = 0;
|
||
}
|
||
else {
|
||
|
||
*Compressed += ( *Uncompressed - '0' );
|
||
Packed = 1;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case '(':
|
||
case ')':
|
||
case ' ':
|
||
case 't':
|
||
case 'T':
|
||
case 'p':
|
||
case 'P':
|
||
case 'w':
|
||
case 'W':
|
||
case ',':
|
||
case '-':
|
||
case '@':
|
||
case '*':
|
||
case '#':
|
||
|
||
// if the byte was packed then we unpack it
|
||
|
||
if ( Packed ) {
|
||
*Compressed += UNPACKED_DIGIT;
|
||
++Compressed;
|
||
Packed = 0;
|
||
}
|
||
|
||
if ((CharPtr=strchr(CompressMap, *Uncompressed)) == NULL) {
|
||
free(UncompressedPtr);
|
||
free(CompressedPtr);
|
||
return( ERROR_BAD_CALLBACK_NUMBER );
|
||
}
|
||
|
||
*Compressed = (UCHAR)(COMPRESS_MAP_BEGIN+
|
||
(UCHAR)(CharPtr-CompressMap));
|
||
Compressed++;
|
||
break;
|
||
|
||
default:
|
||
|
||
// if the chracter is none of the above specially recognized
|
||
// characters then copy the value + UNPACKED_OTHER to make it
|
||
// possible to decompress at the other end. [ 6/4/96 RamC ]
|
||
|
||
if ( Packed) {
|
||
*Compressed += UNPACKED_DIGIT;
|
||
++Compressed;
|
||
Packed = 0;
|
||
}
|
||
*Compressed = *Uncompressed + UNPACKED_OTHER;
|
||
Compressed++;
|
||
}
|
||
|
||
}
|
||
|
||
free(UncompressedPtr);
|
||
|
||
// If we are in the middle of packing something
|
||
// then we unpack it
|
||
|
||
if ( Packed )
|
||
*Compressed += UNPACKED_DIGIT;
|
||
|
||
// Check if it will fit in the userparms field or not
|
||
|
||
if ( strlen( CompressedPtr ) > UP_LEN_DIAL ) {
|
||
free(CompressedPtr);
|
||
return( ERROR_BAD_LENGTH );
|
||
}
|
||
|
||
// convert to unicode string before returning
|
||
|
||
mbstowcs(CompNumber, CompressedPtr, MAX_PHONE_NUMBER_LEN);
|
||
|
||
free(CompressedPtr);
|
||
|
||
return(0);
|
||
|
||
}
|
||
|
||
|
||
USHORT
|
||
DecompressPhoneNumber(
|
||
IN LPWSTR CompNumber,
|
||
OUT LPWSTR DecompNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
|
||
Routine Description:
|
||
|
||
Will decompress a phone number.
|
||
|
||
Arguments:
|
||
|
||
CompNumber - Pointer to a compressed phone number.
|
||
DecompNumber - Pointer to a buffer that is large enough to
|
||
hold the Decompressed number.
|
||
|
||
Return Value:
|
||
|
||
0 on success
|
||
|
||
ERROR_BAD_CALLBACK_NUMBER - failure, if the Compressed number
|
||
contains unrecognizable chars.
|
||
|
||
Algortithm Used:
|
||
|
||
We just do the opposite of the algorithm used in CompressPhoneNumber.
|
||
|
||
--*/
|
||
|
||
{
|
||
CHAR * Decompressed;
|
||
CHAR * Compressed;
|
||
CHAR * DecompressedPtr;
|
||
CHAR * CompressedPtr;
|
||
|
||
|
||
if(!(Decompressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
if(!(Compressed = calloc(1, MAX_PHONE_NUMBER_LEN+1))) {
|
||
return(ERROR_NOT_ENOUGH_MEMORY);
|
||
}
|
||
DecompressedPtr = Decompressed;
|
||
CompressedPtr = Compressed;
|
||
|
||
// convert unicode string to multi byte string for decompression
|
||
|
||
wcstombs(Compressed, CompNumber, MAX_PHONE_NUMBER_LEN+1);
|
||
|
||
for(; *Compressed; Compressed++, Decompressed++ ) {
|
||
|
||
// If this byte is packed then we unpack it
|
||
|
||
if ( (UINT)*Compressed < UNPACKED_DIGIT ) {
|
||
*Decompressed = (UCHAR)(((*Compressed) / 10) + '0' );
|
||
*(++Decompressed) = (UCHAR)( ((*Compressed) % 10) + '0' );
|
||
continue;
|
||
}
|
||
|
||
// we need to special case number 32 which maps to a blank
|
||
|
||
if ( (UINT)*Compressed == COMPRESS_MAP_END ) {
|
||
*Decompressed = (UCHAR) '3';
|
||
*(++Decompressed) = (UCHAR)'2';
|
||
continue;
|
||
}
|
||
|
||
// the number is an unpacked digit
|
||
|
||
if ( (UINT)*Compressed < COMPRESS_MAP_BEGIN ) {
|
||
*Decompressed = (UCHAR)((*Compressed -(UCHAR)UNPACKED_DIGIT ) +
|
||
'0' );
|
||
continue;
|
||
}
|
||
|
||
// Otherwise the byte was not packed
|
||
|
||
if ( (UINT)*Compressed < UNPACKED_OTHER ) {
|
||
*Decompressed = CompressMap[(*Compressed -
|
||
(UCHAR)COMPRESS_MAP_BEGIN)];
|
||
continue;
|
||
}
|
||
|
||
// otherwise the byte is an unpacked character [ 6/4/96 RamC ]
|
||
|
||
*Decompressed = *Compressed - UNPACKED_OTHER;
|
||
}
|
||
|
||
// convert to unicode string before returning
|
||
|
||
mbstowcs(DecompNumber, DecompressedPtr, MAX_PHONE_NUMBER_LEN+1);
|
||
|
||
free(DecompressedPtr);
|
||
free(CompressedPtr);
|
||
return( 0 );
|
||
|
||
}
|