XipZ
Mini packer ▶►▸ for small programs.
qadz.cc
Go to the documentation of this file.
1 #include <algorithm>
2 #include <fstream>
3 #include <iostream>
4 #include <iterator>
5 #include <vector>
6 #include <boost/format.hpp>
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <limits.h>
10 #include "data.hh"
11 #include "decrunchqadzstub.inc"
12 
22 #define LOOK_BACK 255
23 #define MAX_LEN 128
24 #define MAX_PLAIN_LEN 127
25 
26 using namespace std;
27 using boost::format;
28 
29 int decrunch_main(int argc, char **argv) {
30  FILE *inpf;
31  int c, i;
32  char buf[1024];
33  long bufidx = 0;
34 
35  switch(argc) {
36  case 1:
37  inpf = stdin;
38  break;
39  case 2:
40  if((inpf = fopen(argv[1], "r")) == NULL) {
41  perror("Can not open file");
42  return 2;
43  }
44  break;
45  default:
46  fprintf(stderr, "Usage: qadd [FILENAME]\n");
47  return 1;
48  }
49  while((c = fgetc(inpf)) != EOF) {
50  signed char code = c;
51  if(code > 0) {
52  while(code-- > 0) {
53  c = fgetc(inpf);
54  buf[bufidx++ % sizeof(buf)] = c;
55  putchar(c);
56  }
57  } else if(code < 0) {
58  unsigned char pos = fgetc(inpf);
59  for(i = code; i < 0; ++i) {
60  c = buf[(bufidx - pos) % sizeof(buf)];
61  putchar(c);
62  buf[bufidx++ % sizeof(buf)] = c;
63  }
64  } else
65  break;
66  }
67  if(inpf != stdin) if(fclose(inpf) == EOF) perror("Error closing file");
68  return 0;
69 }
70 
71 
72 std::ostream &write_qadz_stub(std::ostream &out, uint16_t size, uint16_t loadaddr, uint16_t jmp) {
73  // Create a local copy.
74  std::vector<uint8_t> stub(decrunchqadzstub, decrunchqadzstub + decrunchqadzstub_len);
75 // 00000000 01 08 0a 08 02 03 9e 32 30 36 31 00 00 00 a2 08 |.......2061.....|
76 // 00000010 bd 31 08 95 58 ca 10 f8 20 bf a3 78 b9 3a 08 99 |.1..X... ..x.:..|
77 // 00000020 f7 00 c8 d0 f7 e6 59 a9 3c 85 26 a9 03 85 27 4c |......Y.<.&...'L|
78 // 00000030 f7 00 00 10 a2 08 54 37 44 a2 08 a0 00 b1 58 30 |......T7D.....X0|
79 // 00000040 1d d0 03 4c 3c 03 aa a8 e6 58 d0 02 e6 59 b1 58 |...L<....X...Y.X|
80 // 00000050 91 26 88 10 f9 20 45 01 20 52 01 4c f7 00 49 ff |.&... E. R.L..I.|
81 // 00000060 aa e8 c8 b1 58 8d 28 01 a5 26 38 e9 00 85 28 a5 |....X.(..&8...(.|
82 // 00000070 27 e9 00 85 29 8a a8 b1 28 91 26 88 10 f9 20 52 |'...)...(.&... R|
83 // 00000080 01 a2 02 20 45 01 4c f7 00 8a 18 65 58 85 58 a5 |... E.L....eX.X.|
84 // 00000090 59 69 00 85 59 60 8a 18 65 26 85 26 a5 27 69 00 |Yi..Y`..e&.&.'i.|
85 // 000000a0 85 27 60 |.'`|
86  const int POS_OF_JMP = 0x44;
87  const int POS_OF_END_OF_CDATA = 0x34;
88  //const int POS_OF_BEGIN_OF_CDATA = 0x39;
89  const int POS_OF_DEST_LOW = 0x28;
90  const int POS_OF_DEST_HIGH = 0x2c;
91  unsigned endptr = stub.at(POS_OF_END_OF_CDATA) | (stub.at(POS_OF_END_OF_CDATA + 1) << 8);
92  // unsigned beginptr = stub.at(POS_OF_BEGIN_OF_CDATA) | (stub.at(POS_OF_BEGIN_OF_CDATA + 1) << 8);
93 
94  // Assign new end of compressed data.
95  endptr += size; // Add number of bytes of compressed data.
96  endptr += 1; // End pointer must point to the byte *after* the data.
97  stub.at(POS_OF_END_OF_CDATA) = endptr & 0xFF;
98  stub.at(POS_OF_END_OF_CDATA + 1) = (endptr >> 8) & 0xFF;
99  // Assign the new jmp position.
100  stub.at(POS_OF_JMP) = jmp & 0xFF;
101  stub.at(POS_OF_JMP + 1) = (jmp >> 8) & 0xFF;
102  // Assign destination address.
103  stub.at(POS_OF_DEST_LOW) = loadaddr & 0xFF;
104  stub.at(POS_OF_DEST_HIGH) = (loadaddr >> 8) & 0xFF;
105  // Set the maximal read position high-byte.
106  //stub.at(POS_OF_STOPREADING) = 0x10; // Todo: configurable!
107  // Now copy the modified stub.
108  std::copy(stub.begin(), stub.end(), std::ostream_iterator<unsigned char>(out));
109  return out;
110 }
111 
112 
113 
114 std::vector<uint8_t> crunch_qadz(const Data &data) {
115  long datasize = static_cast<long>(data.size());
116  struct Outclass {
117  std::vector<uint8_t> buf;
118  std::vector<uint8_t> out;
119 
120  Outclass() {}
121  ~Outclass() {
122  putc(0);
123  flush();
124  }
125  void flush() {
126  if(!buf.empty()) {
127  out.push_back(static_cast<uint8_t>(buf.size()));
128  copy(buf.begin(), buf.end(), back_inserter(out));
129  buf.clear();
130  }
131  }
132  void putc(uint8_t c) {
133  buf.push_back(c);
134  if(buf.size() == MAX_PLAIN_LEN) {
135  flush();
136  }
137  }
138  void puttoken(int pos, int len) {
139  flush();
140  out.push_back(static_cast<uint8_t>(-len));
141  out.push_back(static_cast<uint8_t>(pos));
142  }
143  } outclass;
144 
145  /* This is not the fastest nor the smartest way to perform the
146  search. Improve in future! */
147  for(long pos = 0; pos < datasize; ++pos) {
148  long posi = LONG_MIN;
149  int cmpi = INT_MIN;
150  int cmpj;
151  int max_look_back;
152  int match = INT_MIN;
153  // Move backwards from the current position.
154  if(pos >= LOOK_BACK) {
155  // There is enough space to do a full look back.
156  max_look_back = LOOK_BACK;
157  } else {
158  // Only go back to the beginning.
159  max_look_back = pos;
160  }
161 #ifdef DEBUG
162  std::cout << "pos: " << pos << " max_look_back: " << max_look_back << std::endl;
163 #endif
164  for(cmpj = max_look_back; cmpj > 0; --cmpj) {
165  // Inner loop for comparison.
166  for(cmpi = 0; cmpi < (cmpj < MAX_LEN ? cmpj : MAX_LEN); ++cmpi) {
167  if(pos + cmpi >= datasize) {
168  // End of data reached.
169  break;
170  }
171  if(data[pos - cmpj + cmpi] != data[pos + cmpi]) {
172  break;
173  }
174  //std::cout << format("pos=%lu '%c' cmpi=%d cmpj=%d\n") % pos % data[pos] % cmpi % cmpj;
175  }
176  //std::cout << format("cmpi=%d match=%lu → ") % cmpi % match;
177  if(cmpi > match) {
178  posi = cmpj;
179  match = cmpi;
180  }
181  //std::cout << format("cmpi=%d match=%lu\n") % cmpi % match;
182  }
183  if(match < 3) {
184  outclass.putc(data[pos]);
185  } else {
186  outclass.puttoken(posi, match);
187  //std::cout << format("[pos=%ld, posi=%ld, match=%ld]") % pos % posi % match;
188  pos += match - 1;
189  }
190  }
191  outclass.flush();
192  return outclass.out;
193 }
crunch_qadz
std::vector< uint8_t > crunch_qadz(const Data &data)
Definition: qadz.cc:114
Data
Input data type.
Definition: data.hh:20
Data::size
std::vector< uint8_t >::size_type size() const
get data size
Definition: data.hh:54
POS_OF_JMP
#define POS_OF_JMP
Position in the stub where the address is stored at which the final JMP is performed.
Definition: xipz.cc:50
POS_OF_END_OF_CDATA
#define POS_OF_END_OF_CDATA
Position in the stub where the end of the compressed data is stored.
Definition: xipz.cc:42
write_qadz_stub
std::ostream & write_qadz_stub(std::ostream &out, uint16_t size, uint16_t loadaddr, uint16_t jmp)
write the decrunch stub
Definition: qadz.cc:72
data.hh
Binary data handling.