]> git.draconx.ca Git - upkg.git/blob - src/pack.c
libupkg: Add signed integer unpacking to fix incorrect signedness issue.
[upkg.git] / src / pack.c
1 /*
2  *  upkg: tool for manipulating Unreal Tournament packages.
3  *  Copyright (C) 2009 Nick Bowler
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <stdio.h>
21 #include <limits.h>
22
23 #include "pack.h"
24
25 /* Unsigned integer packing. */
26 #define DEFPACK_BE(bits, type) void pack_ ## bits ## _be ( \
27         unsigned char *out, type v \
28 ) { \
29         unsigned i; \
30         for (i = 1; i <= bits/8; i++) { \
31                 out[bits/8 - i] = v % 256; \
32                 v /= 256; \
33         } \
34 }
35
36 #define DEFPACK_LE(bits, type) void pack_ ## bits ## _le ( \
37         unsigned char *out, type v \
38 ) { \
39         unsigned i; \
40         for (i = 0; i < bits/8; i++) { \
41                 out[i] = v % 256; \
42                 v /= 256; \
43         } \
44 }
45
46 DEFPACK_BE(16, unsigned short)
47 DEFPACK_BE(32, unsigned long)
48 #ifdef ULLONG_MAX
49 DEFPACK_BE(64, unsigned long long)
50 #endif
51
52 DEFPACK_LE(16, unsigned short)
53 DEFPACK_LE(32, unsigned long)
54 #ifdef ULLONG_MAX
55 DEFPACK_LE(64, unsigned long long)
56 #endif
57
58 #define DEFUNPACK_BE(bits, type) type unpack_ ## bits ## _be ( \
59         unsigned char *in \
60 ) { \
61         type v = 0; \
62         unsigned i; \
63         for (i = 0; i < bits/8; i++) { \
64                 v *= 256; \
65                 v += in[i]; \
66         } \
67         return v; \
68 }
69
70 #define DEFUNPACK_LE(bits, type) type unpack_ ## bits ## _le ( \
71         unsigned char *in \
72 ) { \
73         type v = 0; \
74         unsigned i; \
75         for (i = 1; i <= bits/8; i++) { \
76                 v *= 256; \
77                 v += in[bits/8 - i]; \
78         } \
79         return v; \
80 }
81
82 DEFUNPACK_BE(16, unsigned short)
83 DEFUNPACK_BE(32, unsigned long)
84 #ifdef ULLONG_MAX
85 DEFUNPACK_BE(64, unsigned long long)
86 #endif
87
88 DEFUNPACK_LE(16, unsigned short)
89 DEFUNPACK_LE(32, unsigned long)
90 #ifdef ULLONG_MAX
91 DEFUNPACK_LE(64, unsigned long long)
92 #endif
93
94 /*
95  * Two's complement signed integer packing.  This is unlikely to work on
96  * systems that don't themselves use two's complement.
97  */
98
99 #define DEFUNPACK_SBE(bits, max, type) type unpack_s ## bits ## _be ( \
100         unsigned char *in \
101 ) { \
102         type v = 0; \
103         unsigned i; \
104         int sign = (in[0] & 0x80) ? 1 : 0; \
105         in[0] &= 0x7f; \
106         for (i = 0; i < bits/8; i++) { \
107                 v *= 256; \
108                 v += in[i]; \
109         } \
110         return sign*(-max-1) + v; \
111 }
112
113 #define DEFUNPACK_SLE(bits, max, type) type unpack_s ## bits ## _le ( \
114         unsigned char *in \
115 ) { \
116         type v = 0; \
117         unsigned i; \
118         int sign = (in[bits/8 - 1] & 0x80) ? 1 : 0; \
119         in[bits/8 - 1] &= 0x7f; \
120         for (i = 1; i <= bits/8; i++) { \
121                 v *= 256; \
122                 v += in[bits/8 - i]; \
123         } \
124         return sign*(-max-1) + v; \
125 }
126
127 DEFUNPACK_SBE(16, 32767, short)
128 DEFUNPACK_SBE(32, 2147483647l, long)
129 #ifdef LLONG_MAX
130 DEFUNPACK_SBE(64, 9223372036854775807ll, long long)
131 #endif
132
133 DEFUNPACK_SLE(16, 32767, short)
134 DEFUNPACK_SLE(32, 2147483647l, long)
135 #ifdef LLONG_MAX
136 DEFUNPACK_SLE(64, 9223372036854775807ll, long long)
137 #endif