Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:16

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup rtems_rtl
0007  *
0008  * @brief RTEMS Run-Time Linker Object Compression manages a compress
0009  *        stream of data.
0010  */
0011 
0012 /*
0013  *  COPYRIGHT (c) 2012, 2018 Chris Johns <chrisj@rtems.org>
0014  *
0015  * Redistribution and use in source and binary forms, with or without
0016  * modification, are permitted provided that the following conditions
0017  * are met:
0018  * 1. Redistributions of source code must retain the above copyright
0019  *    notice, this list of conditions and the following disclaimer.
0020  * 2. Redistributions in binary form must reproduce the above copyright
0021  *    notice, this list of conditions and the following disclaimer in the
0022  *    documentation and/or other materials provided with the distribution.
0023  *
0024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0027  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0028  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0029  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0030  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0031  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0032  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0033  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0034  * POSSIBILITY OF SUCH DAMAGE.
0035  */
0036 
0037 #ifdef HAVE_CONFIG_H
0038 #include "config.h"
0039 #endif
0040 
0041 #include <errno.h>
0042 #include <string.h>
0043 #include <unistd.h>
0044 #include <inttypes.h>
0045 #include <rtems/inttypes.h>
0046 
0047 #include <rtems/rtl/rtl-allocator.h>
0048 #include <rtems/rtl/rtl-obj-comp.h>
0049 #include "rtl-error.h"
0050 #include <rtems/rtl/rtl-trace.h>
0051 
0052 #include "fastlz.h"
0053 
0054 #include <stdio.h>
0055 
0056 bool
0057 rtems_rtl_obj_comp_open (rtems_rtl_obj_comp* comp,
0058                          size_t              size)
0059 {
0060   comp->cache  = NULL;
0061   comp->fd = -1;
0062   comp->compression = RTEMS_RTL_COMP_LZ77;
0063   comp->offset = 0;
0064   comp->size   = size;
0065   comp->level  = 0;
0066   comp->buffer = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, size, false);
0067   if (!comp->buffer)
0068   {
0069     rtems_rtl_set_error (ENOMEM, "no memory for compressor buffer");
0070     return false;
0071   }
0072   comp->read = 0;
0073   return true;
0074 }
0075 
0076 void
0077 rtems_rtl_obj_comp_close (rtems_rtl_obj_comp* comp)
0078 {
0079   rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, comp->buffer);
0080   comp->cache = NULL;
0081   comp->fd = -1;
0082   comp->compression = RTEMS_RTL_COMP_LZ77;
0083   comp->level = 0;
0084   comp->size = 0;
0085   comp->offset = 0;
0086   comp->read = 0;
0087 }
0088 
0089 void
0090 rtems_rtl_obj_comp_set (rtems_rtl_obj_comp*  comp,
0091                         rtems_rtl_obj_cache* cache,
0092                         int                  fd,
0093                         int                  compression,
0094                         off_t                offset)
0095 {
0096   comp->cache = cache;
0097   comp->fd = fd;
0098   comp->compression = compression;
0099   comp->offset = offset;
0100   comp->level = 0;
0101   comp->read = 0;
0102 }
0103 
0104 bool
0105 rtems_rtl_obj_comp_read (rtems_rtl_obj_comp* comp,
0106                          void*               buffer,
0107                          size_t              length)
0108 {
0109   uint8_t* bin = buffer;
0110 
0111   if (!comp->cache)
0112   {
0113     rtems_rtl_set_error (EINVAL, "not open");
0114     return false;
0115   }
0116 
0117   if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0118     printf ("rtl:  comp: %2d: fd=%d length=%zu level=%zu offset=%" PRIdoff_t " area=[%"
0119             PRIdoff_t ",%" PRIdoff_t "] read=%" PRIu32 " size=%zu\n",
0120             comp->fd, comp->cache->fd, length, comp->level, comp->offset,
0121             comp->offset, comp->offset + length,
0122             comp->read, comp->size);
0123 
0124   if (comp->fd != comp->cache->fd)
0125   {
0126     comp->level = 0;
0127   }
0128 
0129   while (length)
0130   {
0131     size_t buffer_level;
0132 
0133     buffer_level = length > comp->level ? comp->level : length;
0134 
0135     if (buffer_level)
0136     {
0137       if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0138         printf ("rtl:  comp: copy: length=%zu\n",
0139                 buffer_level);
0140 
0141       memcpy (bin, comp->buffer, buffer_level);
0142 
0143       if ((comp->level - buffer_level) != 0)
0144       {
0145         if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0146           printf ("rtl:  comp: copy-down: level=%zu length=%zu\n",
0147                   comp->level, comp->level - buffer_level);
0148 
0149         memmove (comp->buffer,
0150                  comp->buffer + buffer_level,
0151                  comp->level - buffer_level);
0152       }
0153 
0154       bin += buffer_level;
0155       length -= buffer_level;
0156       comp->level -= buffer_level;
0157       comp->read += buffer_level;
0158     }
0159 
0160     if (length)
0161     {
0162       uint8_t* input = NULL;
0163       uint16_t block_size;
0164       size_t   in_length = sizeof (block_size);
0165       int      decompressed;
0166 
0167       if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0168         printf ("rtl:  comp: read block-size: offset=%" PRIdoff_t "\n",
0169                 comp->offset);
0170 
0171       if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
0172                                      (void**) &input, &in_length))
0173         return false;
0174 
0175       block_size = (input[0] << 8) | input[1];
0176 
0177       comp->offset += sizeof (block_size);
0178 
0179       in_length = block_size;
0180 
0181       if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0182         printf ("rtl:  comp: read block: offset=%" PRIdoff_t " size=%u\n",
0183                 comp->offset, block_size);
0184 
0185       if (!rtems_rtl_obj_cache_read (comp->cache, comp->fd, comp->offset,
0186                                      (void**) &input, &in_length))
0187         return false;
0188 
0189       if (in_length != block_size)
0190       {
0191         rtems_rtl_set_error (EIO, "compressed read failed: bs=%u in=%zu",
0192                              block_size, in_length);
0193         return false;
0194       }
0195 
0196       switch (comp->compression)
0197       {
0198         case RTEMS_RTL_COMP_NONE:
0199           memcpy (comp->buffer, input, in_length);
0200           decompressed = in_length;
0201           break;
0202 
0203         case RTEMS_RTL_COMP_LZ77:
0204           decompressed = fastlz_decompress (input, in_length,
0205                                             comp->buffer, comp->size);
0206           if (decompressed == 0)
0207           {
0208             rtems_rtl_set_error (EBADF, "decompression failed");
0209             return false;
0210           }
0211           break;
0212 
0213         default:
0214           rtems_rtl_set_error (EINVAL, "bad compression type");
0215           return false;
0216       }
0217 
0218       comp->offset += block_size;
0219 
0220       comp->level = decompressed;
0221 
0222       if (rtems_rtl_trace (RTEMS_RTL_TRACE_COMP))
0223         printf ("rtl:  comp: expand: offset=%" PRIdoff_t \
0224                 " level=%zu read=%" PRIu32 "\n",
0225                 comp->offset, comp->level, comp->read);
0226     }
0227   }
0228 
0229   return true;
0230 }