1 /* 2 * PackBits.cpp 3 * Copyright 1999-2000 Y.Takagi. All Rights Reserved. 4 */ 5 6 //#define DBG_CON_STREAM 7 8 #ifdef DBG_CON_STREAM 9 #include <fstream> 10 #endif 11 12 #include <stdio.h> 13 #include <string.h> 14 #include "PackBits.h" 15 16 17 using namespace std; 18 19 20 #define MAXINBYTES 127 21 #define CONTROL1(i) -i 22 #define CONTROL2(i) i 23 24 enum STATUS { 25 INITIAL, 26 UNDECIDED, 27 UNMATCHED, 28 MATCHED 29 }; 30 31 #define WRITE_TO_RUN_BUF(byte) \ 32 { \ 33 if (write) \ 34 *runbuf ++ = byte; \ 35 else \ 36 runbuf ++; \ 37 } 38 39 #define WRITE_CONTROL(byte) \ 40 { \ 41 if (write) \ 42 *control = byte; \ 43 } 44 45 template <bool write> 46 class PackBits { 47 public: 48 static int Run(unsigned char* destination, const unsigned char* source, int n) 49 { 50 int i; 51 unsigned char* control; 52 unsigned char* runbuf; 53 unsigned char thisbyte; 54 unsigned char runbyte; 55 STATUS status; 56 57 i = 0; 58 status = INITIAL; 59 control = runbuf = destination; 60 runbyte = *source++; 61 62 while (--n) { 63 thisbyte = *source++; 64 switch (status) { 65 case INITIAL: 66 control = runbuf++; 67 WRITE_TO_RUN_BUF(runbyte); 68 if (thisbyte == runbyte) { 69 status = UNDECIDED; 70 } else { 71 runbyte = thisbyte; 72 status = UNMATCHED; 73 } 74 i = 1; 75 break; 76 77 case UNDECIDED: 78 if (i == MAXINBYTES) { 79 WRITE_CONTROL(CONTROL2(i)); 80 WRITE_TO_RUN_BUF(runbyte); 81 runbyte = thisbyte; 82 status = INITIAL; 83 } else if (thisbyte == runbyte) { 84 if (i > 1) { 85 WRITE_CONTROL(CONTROL2(i - 2)); 86 control = runbuf - 1; 87 } 88 i = 2; 89 status = MATCHED; 90 } else { 91 WRITE_TO_RUN_BUF(runbyte); 92 runbyte = thisbyte; 93 status = UNMATCHED; 94 i++; 95 } 96 break; 97 98 case UNMATCHED: 99 if (i == MAXINBYTES) { 100 WRITE_CONTROL(CONTROL2(i)); 101 status = INITIAL; 102 } else { 103 if (thisbyte == runbyte) { 104 status = UNDECIDED; 105 } 106 i++; 107 } 108 WRITE_TO_RUN_BUF(runbyte); 109 runbyte = thisbyte; 110 break; 111 112 case MATCHED: 113 if ((thisbyte != runbyte) || (i == MAXINBYTES)) { 114 runbuf = control; 115 WRITE_TO_RUN_BUF(CONTROL1(i)); 116 WRITE_TO_RUN_BUF(runbyte); 117 runbyte = thisbyte; 118 status = INITIAL; 119 } else { 120 i++; 121 } 122 break; 123 } 124 } 125 126 switch (status) { 127 case INITIAL: 128 WRITE_TO_RUN_BUF(CONTROL2(1)); 129 break; 130 case UNDECIDED: 131 case UNMATCHED: 132 WRITE_CONTROL(CONTROL2(i)); 133 break; 134 case MATCHED: 135 runbuf = control; 136 WRITE_TO_RUN_BUF(CONTROL1(i)); 137 break; 138 } 139 WRITE_TO_RUN_BUF(runbyte); 140 141 return runbuf - destination; 142 } 143 }; 144 145 146 int pack_bits_size(const unsigned char* source, int size) 147 { 148 PackBits<false> compressedSizeCalculator; 149 return compressedSizeCalculator.Run(NULL, source, size); 150 } 151 152 int pack_bits(unsigned char* destination, const unsigned char* source, int size) 153 { 154 PackBits<true> compressor; 155 return compressor.Run(destination, source, size); 156 } 157 158 #ifdef DBG_CON_STREAM 159 int main(int argc, char **argv) 160 { 161 if (argc < 2) { 162 return -1; 163 } 164 165 FILE *input = fopen(*++argv, "rb"); 166 if (input == NULL) { 167 return -1; 168 } 169 170 FILE *output = fopen("rle.out", "wb"); 171 if (output == NULL) { 172 fclose(input); 173 return -1; 174 } 175 176 fseek(input, 0, SEEK_END); 177 long size = ftell(input); 178 fseek(input, 0, SEEK_SET); 179 180 unsigned char* source = new unsigned char[size]; 181 fread(source, size, 1, input); 182 183 long outSize = pack_bits_size(source, size); 184 printf("input size: %d\noutput size: %d\n", (int)size, (int)outSize); 185 186 unsigned char* destination = new unsigned char[outSize]; 187 188 int cnt = pack_bits(destination, source, size); 189 190 fwrite(destination, cnt, 1, output); 191 192 fclose(input); 193 fclose(output); 194 195 delete [] source; 196 delete [] destination; 197 198 } 199 #endif 200