Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
R
reform-boundary-uboot
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Reform
reform-boundary-uboot
Commits
ae644800
Commit
ae644800
authored
23 years ago
by
Wolfgang Denk
Browse files
Options
Downloads
Patches
Plain Diff
Initial revision
parent
012771d8
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
fs/jffs2/mini_inflate.c
+396
-0
396 additions, 0 deletions
fs/jffs2/mini_inflate.c
with
396 additions
and
0 deletions
fs/jffs2/mini_inflate.c
0 → 100644
+
396
−
0
View file @
ae644800
/*-------------------------------------------------------------------------
* Filename: mini_inflate.c
* Version: $Id: mini_inflate.c,v 1.3 2002/01/24 22:58:42 rfeany Exp $
* Copyright: Copyright (C) 2001, Russ Dill
* Author: Russ Dill <Russ.Dill@asu.edu>
* Description: Mini inflate implementation (RFC 1951)
*-----------------------------------------------------------------------*/
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include
<config.h>
#if (CONFIG_COMMANDS & CFG_CMD_JFFS2)
#include
<jffs2/mini_inflate.h>
/* The order that the code lengths in section 3.2.7 are in */
static
unsigned
char
huffman_order
[]
=
{
16
,
17
,
18
,
0
,
8
,
7
,
9
,
6
,
10
,
5
,
11
,
4
,
12
,
3
,
13
,
2
,
14
,
1
,
15
};
inline
void
cramfs_memset
(
int
*
s
,
const
int
c
,
size
n
)
{
n
--
;
for
(;
n
>
0
;
n
--
)
s
[
n
]
=
c
;
s
[
0
]
=
c
;
}
/* associate a stream with a block of data and reset the stream */
static
void
init_stream
(
struct
bitstream
*
stream
,
unsigned
char
*
data
,
void
*
(
*
inflate_memcpy
)(
void
*
,
const
void
*
,
size
))
{
stream
->
error
=
NO_ERROR
;
stream
->
memcpy
=
inflate_memcpy
;
stream
->
decoded
=
0
;
stream
->
data
=
data
;
stream
->
bit
=
0
;
/* The first bit of the stream is the lsb of the
* first byte */
/* really sorry about all this initialization, think of a better way,
* let me know and it will get cleaned up */
stream
->
codes
.
bits
=
8
;
stream
->
codes
.
num_symbols
=
19
;
stream
->
codes
.
lengths
=
stream
->
code_lengths
;
stream
->
codes
.
symbols
=
stream
->
code_symbols
;
stream
->
codes
.
count
=
stream
->
code_count
;
stream
->
codes
.
first
=
stream
->
code_first
;
stream
->
codes
.
pos
=
stream
->
code_pos
;
stream
->
lengths
.
bits
=
16
;
stream
->
lengths
.
num_symbols
=
288
;
stream
->
lengths
.
lengths
=
stream
->
length_lengths
;
stream
->
lengths
.
symbols
=
stream
->
length_symbols
;
stream
->
lengths
.
count
=
stream
->
length_count
;
stream
->
lengths
.
first
=
stream
->
length_first
;
stream
->
lengths
.
pos
=
stream
->
length_pos
;
stream
->
distance
.
bits
=
16
;
stream
->
distance
.
num_symbols
=
32
;
stream
->
distance
.
lengths
=
stream
->
distance_lengths
;
stream
->
distance
.
symbols
=
stream
->
distance_symbols
;
stream
->
distance
.
count
=
stream
->
distance_count
;
stream
->
distance
.
first
=
stream
->
distance_first
;
stream
->
distance
.
pos
=
stream
->
distance_pos
;
}
/* pull 'bits' bits out of the stream. The last bit pulled it returned as the
* msb. (section 3.1.1)
*/
inline
unsigned
long
pull_bits
(
struct
bitstream
*
stream
,
const
unsigned
int
bits
)
{
unsigned
long
ret
;
int
i
;
ret
=
0
;
for
(
i
=
0
;
i
<
bits
;
i
++
)
{
ret
+=
((
*
(
stream
->
data
)
>>
stream
->
bit
)
&
1
)
<<
i
;
/* if, before incrementing, we are on bit 7,
* go to the lsb of the next byte */
if
(
stream
->
bit
++
==
7
)
{
stream
->
bit
=
0
;
stream
->
data
++
;
}
}
return
ret
;
}
inline
int
pull_bit
(
struct
bitstream
*
stream
)
{
int
ret
=
((
*
(
stream
->
data
)
>>
stream
->
bit
)
&
1
);
if
(
stream
->
bit
++
==
7
)
{
stream
->
bit
=
0
;
stream
->
data
++
;
}
return
ret
;
}
/* discard bits up to the next whole byte */
static
void
discard_bits
(
struct
bitstream
*
stream
)
{
if
(
stream
->
bit
!=
0
)
{
stream
->
bit
=
0
;
stream
->
data
++
;
}
}
/* No decompression, the data is all literals (section 3.2.4) */
static
void
decompress_none
(
struct
bitstream
*
stream
,
unsigned
char
*
dest
)
{
unsigned
int
length
;
discard_bits
(
stream
);
length
=
*
(
stream
->
data
++
);
length
+=
*
(
stream
->
data
++
)
<<
8
;
pull_bits
(
stream
,
16
);
/* throw away the inverse of the size */
stream
->
decoded
+=
length
;
stream
->
memcpy
(
dest
,
stream
->
data
,
length
);
stream
->
data
+=
length
;
}
/* Read in a symbol from the stream (section 3.2.2) */
static
int
read_symbol
(
struct
bitstream
*
stream
,
struct
huffman_set
*
set
)
{
int
bits
=
0
;
int
code
=
0
;
while
(
!
(
set
->
count
[
bits
]
&&
code
<
set
->
first
[
bits
]
+
set
->
count
[
bits
]))
{
code
=
(
code
<<
1
)
+
pull_bit
(
stream
);
if
(
++
bits
>
set
->
bits
)
{
/* error decoding (corrupted data?) */
stream
->
error
=
CODE_NOT_FOUND
;
return
-
1
;
}
}
return
set
->
symbols
[
set
->
pos
[
bits
]
+
code
-
set
->
first
[
bits
]];
}
/* decompress a stream of data encoded with the passed length and distance
* huffman codes */
static
void
decompress_huffman
(
struct
bitstream
*
stream
,
unsigned
char
*
dest
)
{
struct
huffman_set
*
lengths
=
&
(
stream
->
lengths
);
struct
huffman_set
*
distance
=
&
(
stream
->
distance
);
int
symbol
,
length
,
dist
,
i
;
do
{
if
((
symbol
=
read_symbol
(
stream
,
lengths
))
<
0
)
return
;
if
(
symbol
<
256
)
{
*
(
dest
++
)
=
symbol
;
/* symbol is a literal */
stream
->
decoded
++
;
}
else
if
(
symbol
>
256
)
{
/* Determine the length of the repitition
* (section 3.2.5) */
if
(
symbol
<
265
)
length
=
symbol
-
254
;
else
if
(
symbol
==
285
)
length
=
258
;
else
{
length
=
pull_bits
(
stream
,
(
symbol
-
261
)
>>
2
);
length
+=
(
4
<<
((
symbol
-
261
)
>>
2
))
+
3
;
length
+=
((
symbol
-
1
)
%
4
)
<<
((
symbol
-
261
)
>>
2
);
}
/* Determine how far back to go */
if
((
symbol
=
read_symbol
(
stream
,
distance
))
<
0
)
return
;
if
(
symbol
<
4
)
dist
=
symbol
+
1
;
else
{
dist
=
pull_bits
(
stream
,
(
symbol
-
2
)
>>
1
);
dist
+=
(
2
<<
((
symbol
-
2
)
>>
1
))
+
1
;
dist
+=
(
symbol
%
2
)
<<
((
symbol
-
2
)
>>
1
);
}
stream
->
decoded
+=
length
;
for
(
i
=
0
;
i
<
length
;
i
++
)
{
*
dest
=
dest
[
-
dist
];
dest
++
;
}
}
}
while
(
symbol
!=
256
);
/* 256 is the end of the data block */
}
/* Fill the lookup tables (section 3.2.2) */
static
void
fill_code_tables
(
struct
huffman_set
*
set
)
{
int
code
=
0
,
i
,
length
;
/* fill in the first code of each bit length, and the pos pointer */
set
->
pos
[
0
]
=
0
;
for
(
i
=
1
;
i
<
set
->
bits
;
i
++
)
{
code
=
(
code
+
set
->
count
[
i
-
1
])
<<
1
;
set
->
first
[
i
]
=
code
;
set
->
pos
[
i
]
=
set
->
pos
[
i
-
1
]
+
set
->
count
[
i
-
1
];
}
/* Fill in the table of symbols in order of their huffman code */
for
(
i
=
0
;
i
<
set
->
num_symbols
;
i
++
)
{
if
((
length
=
set
->
lengths
[
i
]))
set
->
symbols
[
set
->
pos
[
length
]
++
]
=
i
;
}
/* reset the pos pointer */
for
(
i
=
1
;
i
<
set
->
bits
;
i
++
)
set
->
pos
[
i
]
-=
set
->
count
[
i
];
}
static
void
init_code_tables
(
struct
huffman_set
*
set
)
{
cramfs_memset
(
set
->
lengths
,
0
,
set
->
num_symbols
);
cramfs_memset
(
set
->
count
,
0
,
set
->
bits
);
cramfs_memset
(
set
->
first
,
0
,
set
->
bits
);
}
/* read in the huffman codes for dynamic decoding (section 3.2.7) */
static
void
decompress_dynamic
(
struct
bitstream
*
stream
,
unsigned
char
*
dest
)
{
/* I tried my best to minimize the memory footprint here, while still
* keeping up performance. I really dislike the _lengths[] tables, but
* I see no way of eliminating them without a sizable performance
* impact. The first struct table keeps track of stats on each bit
* length. The _length table keeps a record of the bit length of each
* symbol. The _symbols table is for looking up symbols by the huffman
* code (the pos element points to the first place in the symbol table
* where that bit length occurs). I also hate the initization of these
* structs, if someone knows how to compact these, lemme know. */
struct
huffman_set
*
codes
=
&
(
stream
->
codes
);
struct
huffman_set
*
lengths
=
&
(
stream
->
lengths
);
struct
huffman_set
*
distance
=
&
(
stream
->
distance
);
int
hlit
=
pull_bits
(
stream
,
5
)
+
257
;
int
hdist
=
pull_bits
(
stream
,
5
)
+
1
;
int
hclen
=
pull_bits
(
stream
,
4
)
+
4
;
int
length
,
curr_code
,
symbol
,
i
,
last_code
;
last_code
=
0
;
init_code_tables
(
codes
);
init_code_tables
(
lengths
);
init_code_tables
(
distance
);
/* fill in the count of each bit length' as well as the lengths
* table */
for
(
i
=
0
;
i
<
hclen
;
i
++
)
{
length
=
pull_bits
(
stream
,
3
);
codes
->
lengths
[
huffman_order
[
i
]]
=
length
;
if
(
length
)
codes
->
count
[
length
]
++
;
}
fill_code_tables
(
codes
);
/* Do the same for the length codes, being carefull of wrap through
* to the distance table */
curr_code
=
0
;
while
(
curr_code
<
hlit
)
{
if
((
symbol
=
read_symbol
(
stream
,
codes
))
<
0
)
return
;
if
(
symbol
==
0
)
{
curr_code
++
;
last_code
=
0
;
}
else
if
(
symbol
<
16
)
{
/* Literal length */
lengths
->
lengths
[
curr_code
]
=
last_code
=
symbol
;
lengths
->
count
[
symbol
]
++
;
curr_code
++
;
}
else
if
(
symbol
==
16
)
{
/* repeat the last symbol 3 - 6
* times */
length
=
3
+
pull_bits
(
stream
,
2
);
for
(;
length
;
length
--
,
curr_code
++
)
if
(
curr_code
<
hlit
)
{
lengths
->
lengths
[
curr_code
]
=
last_code
;
lengths
->
count
[
last_code
]
++
;
}
else
{
/* wrap to the distance table */
distance
->
lengths
[
curr_code
-
hlit
]
=
last_code
;
distance
->
count
[
last_code
]
++
;
}
}
else
if
(
symbol
==
17
)
{
/* repeat a bit length 0 */
curr_code
+=
3
+
pull_bits
(
stream
,
3
);
last_code
=
0
;
}
else
{
/* same, but more times */
curr_code
+=
11
+
pull_bits
(
stream
,
7
);
last_code
=
0
;
}
}
fill_code_tables
(
lengths
);
/* Fill the distance table, don't need to worry about wrapthrough
* here */
curr_code
-=
hlit
;
while
(
curr_code
<
hdist
)
{
if
((
symbol
=
read_symbol
(
stream
,
codes
))
<
0
)
return
;
if
(
symbol
==
0
)
{
curr_code
++
;
last_code
=
0
;
}
else
if
(
symbol
<
16
)
{
distance
->
lengths
[
curr_code
]
=
last_code
=
symbol
;
distance
->
count
[
symbol
]
++
;
curr_code
++
;
}
else
if
(
symbol
==
16
)
{
length
=
3
+
pull_bits
(
stream
,
2
);
for
(;
length
;
length
--
,
curr_code
++
)
{
distance
->
lengths
[
curr_code
]
=
last_code
;
distance
->
count
[
last_code
]
++
;
}
}
else
if
(
symbol
==
17
)
{
curr_code
+=
3
+
pull_bits
(
stream
,
3
);
last_code
=
0
;
}
else
{
curr_code
+=
11
+
pull_bits
(
stream
,
7
);
last_code
=
0
;
}
}
fill_code_tables
(
distance
);
decompress_huffman
(
stream
,
dest
);
}
/* fill in the length and distance huffman codes for fixed encoding
* (section 3.2.6) */
static
void
decompress_fixed
(
struct
bitstream
*
stream
,
unsigned
char
*
dest
)
{
/* let gcc fill in the initial values */
struct
huffman_set
*
lengths
=
&
(
stream
->
lengths
);
struct
huffman_set
*
distance
=
&
(
stream
->
distance
);
cramfs_memset
(
lengths
->
count
,
0
,
16
);
cramfs_memset
(
lengths
->
first
,
0
,
16
);
cramfs_memset
(
lengths
->
lengths
,
8
,
144
);
cramfs_memset
(
lengths
->
lengths
+
144
,
9
,
112
);
cramfs_memset
(
lengths
->
lengths
+
256
,
7
,
24
);
cramfs_memset
(
lengths
->
lengths
+
280
,
8
,
8
);
lengths
->
count
[
7
]
=
24
;
lengths
->
count
[
8
]
=
152
;
lengths
->
count
[
9
]
=
112
;
cramfs_memset
(
distance
->
count
,
0
,
16
);
cramfs_memset
(
distance
->
first
,
0
,
16
);
cramfs_memset
(
distance
->
lengths
,
5
,
32
);
distance
->
count
[
5
]
=
32
;
fill_code_tables
(
lengths
);
fill_code_tables
(
distance
);
decompress_huffman
(
stream
,
dest
);
}
/* returns the number of bytes decoded, < 0 if there was an error. Note that
* this function assumes that the block starts on a byte boundry
* (non-compliant, but I don't see where this would happen). section 3.2.3 */
long
decompress_block
(
unsigned
char
*
dest
,
unsigned
char
*
source
,
void
*
(
*
inflate_memcpy
)(
void
*
,
const
void
*
,
size
))
{
int
bfinal
,
btype
;
struct
bitstream
stream
;
init_stream
(
&
stream
,
source
,
inflate_memcpy
);
do
{
bfinal
=
pull_bit
(
&
stream
);
btype
=
pull_bits
(
&
stream
,
2
);
if
(
btype
==
NO_COMP
)
decompress_none
(
&
stream
,
dest
+
stream
.
decoded
);
else
if
(
btype
==
DYNAMIC_COMP
)
decompress_dynamic
(
&
stream
,
dest
+
stream
.
decoded
);
else
if
(
btype
==
FIXED_COMP
)
decompress_fixed
(
&
stream
,
dest
+
stream
.
decoded
);
else
stream
.
error
=
COMP_UNKNOWN
;
}
while
(
!
bfinal
&&
!
stream
.
error
);
#if 0
putstr("decompress_block start\r\n");
putLabeledWord("stream.error = ",stream.error);
putLabeledWord("stream.decoded = ",stream.decoded);
putLabeledWord("dest = ",dest);
putstr("decompress_block end\r\n");
#endif
return
stream
.
error
?
-
stream
.
error
:
stream
.
decoded
;
}
#endif
/* CFG_CMD_JFFS2 */
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment