source: rtems-tools/linkers/rld-compression.cpp @ 8bb0d53

4.104.115
Last change on this file since 8bb0d53 was db216fe, checked in by Chris Johns <chrisj@…>, on 12/19/12 at 05:22:37

Decompression support added.

The compressor can now decompress LZ77 files.

  • Property mode set to 100644
File size: 5.6 KB
Line 
1/*
2 * Copyright (c) 2012, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16/**
17 * @file
18 *
19 * @ingroup rtems_ld
20 *
21 * @brief RTEMS Linker.
22 *
23 */
24
25#if HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <fstream>
30#include <iostream>
31
32#include <errno.h>
33#include <string.h>
34
35#include <rld.h>
36#include <rld-compression.h>
37
38#include "fastlz.h"
39
40namespace rld
41{
42  namespace compress
43  {
44    compressor::compressor (files::image& image,
45                            size_t        size,
46                            bool          out,
47                            bool          compress)
48      : image (image),
49        size (size),
50        out (out),
51        compress (compress),
52        buffer (0),
53        io (0),
54        level (0),
55        total (0),
56        total_compressed (0)
57    {
58      if (size > 0xffff)
59        throw rld::error ("Size too big, 16 bits only", "compression");
60
61      buffer = new uint8_t[size];
62      io = new uint8_t[size + (size / 10)];
63    }
64
65    compressor::~compressor ()
66    {
67      flush ();
68      delete [] buffer;
69      delete [] io;
70    }
71
72    void
73    compressor::write (const void* data_, size_t length)
74    {
75      if (!out)
76        throw rld::error ("Write on read-only", "compression");
77
78      const uint8_t* data = static_cast <const uint8_t*> (data_);
79
80      while (length)
81      {
82        size_t appending;
83
84        if (length > (size - level))
85          appending = size - level;
86        else
87          appending = length;
88
89        ::memcpy ((void*) (buffer + level), data, appending);
90
91        data += appending;
92        level += appending;
93        length -= appending;
94        total += appending;
95
96        output ();
97      }
98    }
99
100    void
101    compressor::write (files::image& input, off_t offset, size_t length)
102    {
103      if (!out)
104        throw rld::error ("Write on read-only", "compression");
105
106      input.seek (offset);
107
108      while (length)
109      {
110        size_t appending;
111
112        if (length > (size - level))
113          appending = size - level;
114        else
115          appending = length;
116
117        input.read ((void*) (buffer + level), appending);
118
119        level += appending;
120        length -= appending;
121        total += appending;
122
123        output ();
124      }
125    }
126
127    void
128    compressor::read (void* data_, size_t length)
129    {
130      if (out)
131        throw rld::error ("Read on write-only", "compression");
132
133      uint8_t* data = static_cast <uint8_t*> (data_);
134
135      while (length)
136      {
137        input ();
138
139        size_t appending;
140
141        if (length > level)
142          appending = level;
143        else
144          appending = length;
145
146        ::memcpy (data, buffer, appending);
147
148        data += appending;
149        level -= appending;
150        length -= appending;
151        total += appending;
152      }
153    }
154
155    void
156    compressor::read (files::image& output_, off_t offset, size_t length)
157    {
158      if (out)
159        throw rld::error ("Read on write-only", "compression");
160
161      output_.seek (offset);
162
163      while (length)
164      {
165        input ();
166
167        size_t appending;
168
169        if (length > level)
170          appending = level;
171        else
172          appending = length;
173
174        output_.write (buffer, appending);
175
176        level -= appending;
177        length -= appending;
178        total += appending;
179      }
180    }
181
182    void
183    compressor::flush ()
184    {
185      output (true);
186    }
187
188    size_t
189    compressor::transferred () const
190    {
191      return total;
192    }
193
194    size_t
195    compressor::compressed () const
196    {
197      return total_compressed;
198    }
199
200    void
201    compressor::output (bool forced)
202    {
203      if (out && ((forced && level) || (level >= size)))
204      {
205        if (compress)
206        {
207          int     writing = ::fastlz_compress (buffer, level, io);
208          uint8_t header[2];
209
210          if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
211            std::cout << "rtl: comp: offset=" << total_compressed
212                      << " block-size=" << writing << std::endl;
213
214          header[0] = writing >> 8;
215          header[1] = writing;
216
217          image.write (header, 2);
218          image.write (io, writing);
219
220          total_compressed += 2 + writing;
221        }
222        else
223        {
224          image.write (buffer, level);
225        }
226
227        level = 0;
228      }
229    }
230
231    void
232    compressor::input ()
233    {
234      if (!out && (level == 0))
235      {
236        if (compress)
237        {
238          uint8_t header[2];
239
240          image.read (header, 2);
241
242          uint32_t block_size = (((uint32_t) header[0]) << 8) | (uint32_t) header[1];
243
244          if (block_size == 0)
245            throw rld::error ("Block size is invalid (0)", "compression");
246
247          total_compressed += 2 + block_size;
248
249          if (1 || rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
250            std::cout << "rtl: decomp: block-size=" << block_size << std::endl;
251
252          image.read (io, block_size);
253
254          level = ::fastlz_decompress (io, block_size, buffer, size);
255        }
256        else
257        {
258          image.read (buffer, size);
259          level = size;
260        }
261      }
262    }
263
264  }
265}
Note: See TracBrowser for help on using the repository browser.