In: Computer Science
A typical SMS protocol allows 128 distinct ASCII characters to be used in a message. However, to save bandwidth, instead of using straight 8-bit ASCII characters to transfer data (one byte per character), SMS uses 7 bits per character and compacts the bits such that it only requires 140 bytes to send a 160 character message, for an approximately 12.5% savings of bandwidth.
12.5% savings in bandwidth is not good enough. They would like a system that can save up to 25% of the bandwidth. Therefore, a 160 character message must use only 120 bytes of bandwidth. To do this, a character set that uses only 6 bits per character must be developed. This means that the maximum number of distinct characters that can be in the "alphabet" is 64. The Department of Linguistics was consulted, and they decided that a character set that does not contain any lower case letters, but includes nearly all other printable ASCII characters could be used without major issues. Therefore, the following code and values were developed as the alphabet to be used for the SMS System.
Standard Code for Information Interchange (SCII)
Dec Hex Char | Dec Hex Char | Dec Hex Char | Dec Hex Char |
0 00 NULL | 16 10 G | 32 20 W | 48 30 , |
1 01 . | 17 11 H | 33 21 X | 49 31 - |
2 02 / | 18 12 I | 34 22 Y | 50 32 0 |
3 03 : | 19 13 J | 35 23 Z | 51 33 1 |
4 04 ; | 20 14 K | 36 24 Space | 52 34 2 |
5 05 < | 21 15 L | 37 25 ! | 53 35 3 |
6 06 = | 22 16 M | 38 26 " | 54 36 4 |
7 07 > | 23 17 N | 39 27 # | 55 37 5 |
8 08 ? | 24 18 O | 40 28 $ | 56 38 6 |
9 09 @ | 25 19 P | 42 29 % | 57 39 7 |
10 0A A | 26 1A Q | 42 2A & | 58 3A 8 |
11 0B B | 27 1B R | 43 2B ' | 59 3B 9 |
12 0C C | 28 1C S | 44 2C ( | 60 3C [ |
13 0D D | 29 1D T | 45 2D ) | 61 3D \ |
14 0E E | 30 1E U | 46 2E * | 62 3E ] |
15 0F F | 31 1F V | 47 2F + | 63 3F _ |
Note: All printable ASCII characters that are NOT shown in the above table (such as a..z) will be translated to the '#' character. All non-printable ASCII characters will be translated to NULL.
Packing Bits:
The following system is similar to the SMS 7-bit packing system,
except that it packs 6-bit characters in an array. As an example,
suppose a student wishes to send the following text via the SMS
system:
CS IS GREAT!
Using the table above, each character can be given its corresponding Hexadecimal value:
0C 1C 24 12 1C 24 10 1B 0E 0A 1D 25
C S I
S G
R E A T !
Translating the above message into individal 8-bit bytes, we
get:
00001100 00011100 00100100 00010010 00011100 00100100
00010000 00011011 00001110 00001010 00011101 00100101
Since we are going to only use six bits per character, we can
remove the two Most Significant Bits (MSBs) with the following
result:
001100 011100 100100 010010 011100 100100 010000 011011 001110
001010 011101 100101
We will pack the bits into 8-bit bytes. These bytes will be part of
our Packed Array. To do this, we start at the Least Significant Bit
(LSB) of the first character. In this case, it is the letter C with
the bit pattern 001100. The LSB of this pattern is the last 0
(bolded) - 001100. This bit will become the lsb of the first
element in the packed array. We continue, bit by bit, until we have
put the entire character in the first element of the packed array.
Note that there will be two bits that are not yet
initialized:
- - 0 0 1 1 0 0 <- PackedArray[0] (started)
Now we start on the next character, or 011100 (The letter 'S').
Starting at the LSB, we put that bit in the next available bit of
PackedArray[0]: - 0 0 0 1 1 0 0, then the next LSB after
that: 0 0 0 0 1 1 0 0, and we have finished the first
element of PackedArray. However, we have not finished packing the
letter 'S'! We still have four bits left to encode! So, those four
bits will then become the least significant bits of the next
element of PackedArray:
- - - - 0 1 1 1 <- PackedArray[1] (started)
Continuing with the third character (the character '2'), we take
the four LSBs of that character, and add them to the remaining bit
locations:
0 1 0 0 0 1 1 1 <- PackedArray[1] (completed)
However, there are two more bits left to encode from the '2'
character, so they will become the LSBs of the next element of
PackedArray:
- - - - - - 1 1 <- PackedArray[2] (started)
This continues until all of the 6-bit characters have been packed
or encoded into PackedArray. Any remaining bit locations in
PackedArray that are left after all the bits from the message are
encoded, will be set to 0.
So, after the message is encoded into the packed array, the bits in
the array will look like:
00001100 01000111 11100011 00110100 00101001 01110001 00100100
10110100 00111001 01001010 01010111 00000010
Putting these binary bytes as hexadecimal gives:
0C 47 E3 34 29 71 24 B4 39 4A 57 02
So, the original 15 bytes of the message have now been packed into
12 bytes, a reduction by 20%.
Project Specifications:
For this project, you will create a program that will pack and
unpack lines of SMS text. Your program will be menu driven and
contain the following options:
[P]ack and save a line of text (options are 'P' or 'p')
[U]npack and print a line of text (options are 'U' or 'u')
[Q]uit (options are 'Q' or 'q')
If the Pack and save option is chosen, you will prompt the user for
two items (in this order): 1) A filename in which to save the
packed array, and 2) The line of text to pack and save.
If the Unpack option is chosen, you will prompt the user for a
filename which contains a saved message in the packed format.
If the Quit option is chosen... Well, do whatever you think makes
the most sense.
Detailed Specifications:
Program Files
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "sms.h"
#define BIG 160
#define LIL 120
// Set all the elements in the array to null
void ClearArray(char *array, size_t arraySize)
{
int i;
// Loop until reach the end of the array
for (i = 0; i < arraySize; i++)
{
array[i] = 0; // Set element to null
}
}
// Take each byte from the array named origArray, and pack them
into the array named packedArray
void PackArray(unsigned char *packedArray, size_t packedArraySize,
unsigned char *origArray, size_t origArraySize)
{
int i = 0;
int j = 0;
// Loop until reach the end of both arrays
while (i < packedArraySize && j <
origArraySize)
{
packedArray[i] = origArray[j] | (origArray[j + 1] << 6); // A
| B << 6
packedArray[i + 1] = (origArray[j + 1] >> 2) | (origArray[j +
2] << 4); // B >> 2 | C << 4
packedArray[i + 2] = (origArray[j + 2] >> 4) | (origArray[j +
3] << 2); // C >> 4 | D << 2
i += 3;
j += 4;
}
}
// Unpack the packed bits from the array named packedArray into
individual bytes, and store each byte in the array named
newArray
void UnpackArray(unsigned char *newArray, size_t newArraySize,
unsigned char *packedArray, size_t packedArraySize)
{
int i = 0;
int j = 0;
// Loop until reach the end of both arrays
while (i < newArraySize && j < packedArraySize)
{
// 1 << 2, 1 >> 2
newArray[i] = packedArray[j] << 2; // Split shifts into two
statements
newArray[i] = newArray[i] >> 2;
// 1 >> 6 | (2 << 4, 2 >> 2)
newArray[i + 1] = packedArray[j + 1] << 4; // Split shifts
into two statements
newArray[i + 1] = newArray[i + 1] >> 2;
newArray[i + 1] = (packedArray[j] >> 6) | newArray[i +
1];
// 2 >> 4 | (3 << 6, 3 >> 2)
newArray[i + 2] = packedArray[j + 2] << 6; // Split shifts
into two statements
newArray[i + 2] = newArray[i + 2] >> 2;
newArray[i + 2] = (packedArray[j + 1] >> 4) | newArray[i +
2];
// 3 >> 2
newArray[i + 3] = packedArray[j + 2] >> 2;
i += 4;
j += 3;
}
}
int main(int argc, char *argv[])
{
FILE *output, *input; // Create file variables
char buffer[BIG]; // Buffer to read input
char buffbuff[BIG]; // Extra buffer to clear the input stream
char filename[BIG]; // String to hold filenames
unsigned char unpackedArray[BIG];
unsigned char packedArray[LIL];
char choice = 0;
int on = 1;
int i;
while (on == 1)
{
printf("Pack and save a line of text...........P or p\n");
printf("Unpack and print a line of text........U or u\n");
printf("Quit the program.......................Q or q\n");
printf("\n");
printf("Enter a choice: "); // Prompt the user for valid
input
fgets(buffer, BIG, stdin); // Read the input from the keyboard and
store it in the input variable
sscanf(buffer, "%c", &choice); // Extract the character value
from input and store it in choice
printf("\n");
switch (choice)
{
case 'P':
case 'p':
printf("Enter a filename in which to save the packed array: "); //
Prompt the user for an output file
fgets(buffer, BIG, stdin); // Read the input from the keyboard and
store it in the buffer
sscanf(buffer, "%s", filename); // Extract the string from buffer
and store it in filename
ClearArray(buffbuff, sizeof(buffbuff)); // Clear the buffer
printf("\n");
printf("Enter a line of text to pack and save: "); // Prompt the
user for a message
fgets(buffbuff, BIG, stdin); // Read the input from the keyboard
and store it in the buffer
// Copy first 159 characters from buffbuff to buffer
for (i = 0; i < BIG; i++) {
buffer[i] = buffbuff[i];
}
buffer[strlen(buffer) - 1] = 0; // Set the newline character in
buffer to null
// Clear the input stream
while (buffbuff[strlen(buffbuff) - 1] != '\n') {
fgets(buffbuff, BIG, stdin);
}
output = fopen(strcat(filename, ".sms"), "w"); // Open output
file
if (output == NULL) { // Make sure file was opened properly
printf("Couldn't open the file...\n"); // Print error message
break;
}
// Convert ASCII to GMUSCII
for (i = 0; i < BIG; i++) {
unpackedArray[i] = CharToSMS((unsigned char) buffer[i]);
}
PackArray(packedArray, sizeof(packedArray), unpackedArray,
sizeof(unpackedArray)); // Pack the message
fwrite(packedArray, sizeof(unsigned char), LIL, output); // Write
to output file
printf("\n");
fclose(output); // Close the output file
break;
case 'U':
case 'u':
printf("Enter a filename which contains a packed array: "); //
Prompt the user for an output file
fgets(buffer, BIG, stdin); // Read the input from the keyboard and
store it in the buffer
sscanf(buffer, "%s", filename); // Extract the string from buffer
and store it in filename
input = fopen(strcat(filename, ".sms"), "r"); // Open output
file
if (input == NULL) { // Make sure file was opened properly
printf("Couldn't open the file...\n"); // Print error message
break;
}
ClearArray(buffer, sizeof(buffer)); // Clear the buffer
fread(packedArray, sizeof(unsigned char), LIL, input); // Read
from input file
UnpackArray(unpackedArray, sizeof(unpackedArray), packedArray,
sizeof(packedArray)); // Unpack the message
// Convert GMUSCII to ASCII
for (i = 0; i < BIG; i++) {
buffer[i] = SMSToChar(unpackedArray[i]);
}
printf("\n");
printf("%s\n", buffer); // Display the unpacked message
printf("\n");
fclose(input); // Close the input file
break;
case 'Q':
case 'q':
on = 0; // Exit the program
printf("Thanks for using GMU SMS System.\n");
break;
default:
printf("Not a valid choice.\n"); // Display error message.
}
}
return 0;
}
sms.h
#ifndef SMS_H
#define SMS_H
unsigned char CharToSMS(unsigned char X);
unsigned char SMSToChar(unsigned char X);
#endif
sms.c
#include <stdio.h>
#include <stdlib.h>
unsigned char CharToSMS(unsigned char X)
{
unsigned char retVal = 0;
if (X < 32)
retVal = 0;
else if ((X >= 32) && (X <= 45))
retVal = X + 4;
else if ((X >= 46) && (X <= 47))
retVal = X - 45;
else if ((X >= 48) && (X <= 57)) // 0..9
retVal = X + 2;
else if ((X >= 58) && (X <= 64))
retVal = X - 55;
else if ((X >= 65) && (X <= 90)) // A..Z
retVal = X - 55;
else if ((X >= 91) && (X <= 93))
retVal = X - 31;
else if (X == 95)
retVal = 63; // underscore character
else
retVal = 39; // All chars not in alphabet are set to '#'
return retVal;
}
unsigned char SMSToChar(unsigned char X)
{
unsigned char retVal = 0;
if (X == 0)
retVal = 0;
else if ((X >= 1) && (X <= 2))
retVal = X + 45;
else if ((X >= 3) && (X <= 9))
retVal = X + 55;
else if ((X >= 10) && (X <= 35)) // A..Z
retVal = X + 55;
else if ((X >= 36) && (X <= 49))
retVal = X - 4;
else if ((X >= 50) && (X <= 59)) // 0..9
retVal = X - 2;
else if ((X >= 60) && (X <= 62))
retVal = X + 31;
else if (X == 63)
retVal = X + 32;
else
retVal = 0; // This statement should never be reached
return retVal;
}
output
Pack and save a line of text...........P or p
Unpack and print a line of text........U or u
Quit the program.......................Q or q
Enter a choice: p
Enter a filename in which to save the packed array: test
Enter a line of text to pack and save: Hello World
Pack and save a line of text...........P or p
Unpack and print a line of text........U or u
Quit the program.......................Q or q
Enter a choice: u
Enter a filename which contains a packed array: test
H#### W####
Pack and save a line of text...........P or p
Unpack and print a line of text........U or u
Quit the program.......................Q or q
Enter a choice: q
Thanks for using GMU SMS System.
Hope this helps!
Please let me know if any changes needed.
Thank you!