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

4.104.115
Last change on this file since b6d7f5f was 4e9b324, checked in by Chris Johns <chrisj@…>, on 12/21/12 at 06:08:17

Decompressor fixes.

Make reading compressed files more robust returning the amount
of data that can be read. Also add >> operartors to get the
data. Add exceptions when a read fails.

  • Property mode set to 100644
File size: 6.4 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    size_t
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      size_t amount = 0;
136
137      while (length)
138      {
139        input ();
140
141        if (level == 0)
142          break;
143
144        size_t appending;
145
146        if (length > level)
147          appending = level;
148        else
149          appending = length;
150
151        ::memcpy (data, buffer, appending);
152        ::memmove (buffer, buffer + appending, level - appending);
153
154        data += appending;
155        level -= appending;
156        length -= appending;
157        total += appending;
158        amount += appending;
159      }
160
161      return amount;
162    }
163
164    size_t
165    compressor::read (files::image& output_, off_t offset, size_t length)
166    {
167      if (out)
168        throw rld::error ("Read on write-only", "compression");
169
170      output_.seek (offset);
171
172      return read (output_, length);
173    }
174
175    size_t
176    compressor::read (files::image& output_, size_t length)
177    {
178      if (out)
179        throw rld::error ("Read on write-only", "compression");
180
181      size_t amount = 0;
182
183      while (length)
184      {
185        input ();
186
187        if (level == 0)
188          break;
189
190        size_t appending;
191
192        if (length > level)
193          appending = level;
194        else
195          appending = length;
196
197        output_.write (buffer, appending);
198
199        ::memmove (buffer, buffer + appending, level - appending);
200
201        level -= appending;
202        length -= appending;
203        total += appending;
204        amount += appending;
205      }
206
207      return amount;
208    }
209
210    void
211    compressor::flush ()
212    {
213      output (true);
214    }
215
216    size_t
217    compressor::transferred () const
218    {
219      return total;
220    }
221
222    size_t
223    compressor::compressed () const
224    {
225      return total_compressed;
226    }
227
228    off_t
229    compressor::offset () const
230    {
231      return total;
232    }
233
234    void
235    compressor::output (bool forced)
236    {
237      if (out && ((forced && level) || (level >= size)))
238      {
239        if (compress)
240        {
241          int     writing = ::fastlz_compress (buffer, level, io);
242          uint8_t header[2];
243
244          if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
245            std::cout << "rtl: comp: offset=" << total_compressed
246                      << " block-size=" << writing << std::endl;
247
248          header[0] = writing >> 8;
249          header[1] = writing;
250
251          image.write (header, 2);
252          image.write (io, writing);
253
254          total_compressed += 2 + writing;
255        }
256        else
257        {
258          image.write (buffer, level);
259        }
260
261        level = 0;
262      }
263    }
264
265    void
266    compressor::input ()
267    {
268      if (!out && (level == 0))
269      {
270        if (compress)
271        {
272          uint8_t header[2];
273
274          if (image.read (header, 2) == 2)
275          {
276            uint32_t block_size =
277              (((uint32_t) header[0]) << 8) | (uint32_t) header[1];
278
279            if (block_size == 0)
280              throw rld::error ("Block size is invalid (0)", "compression");
281
282            total_compressed += 2 + block_size;
283
284            if (rld::verbose () >= RLD_VERBOSE_FULL_DEBUG)
285              std::cout << "rtl: decomp: block-size=" << block_size
286                        << std::endl;
287
288            if (image.read (io, block_size) != block_size)
289              throw rld::error ("Read past end", "compression");
290
291            level = ::fastlz_decompress (io, block_size, buffer, size);
292          }
293        }
294        else
295        {
296          image.read (buffer, size);
297          level = size;
298        }
299      }
300    }
301
302  }
303}
Note: See TracBrowser for help on using the repository browser.