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