]>
Commit | Line | Data |
---|---|---|
1 | /* model.c | |
2 | * Greg Cook, 26/Jul/2016 | |
3 | */ | |
4 | ||
5 | /* CRC RevEng: arbitrary-precision CRC calculator and algorithm finder | |
6 | * Copyright (C) 2010, 2011, 2012, 2013, 2014, 2015, 2016 Gregory Cook | |
7 | * | |
8 | * This file is part of CRC RevEng. | |
9 | * | |
10 | * CRC RevEng is free software: you can redistribute it and/or modify | |
11 | * it under the terms of the GNU General Public License as published by | |
12 | * the Free Software Foundation, either version 3 of the License, or | |
13 | * (at your option) any later version. | |
14 | * | |
15 | * CRC RevEng is distributed in the hope that it will be useful, | |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 | * GNU General Public License for more details. | |
19 | * | |
20 | * You should have received a copy of the GNU General Public License | |
21 | * along with CRC RevEng. If not, see <https://www.gnu.org/licenses/>. | |
22 | */ | |
23 | ||
24 | /* 2016-02-22: split off preset.c | |
25 | * 2012-03-03: single-line Williams model string conversion | |
26 | * 2011-09-03: added mrev(), mnovel() | |
27 | * 2011-01-17: fixed ANSI C warnings (except preset models) | |
28 | * 2010-12-26: renamed CRC RevEng | |
29 | * 2010-12-18: minor change to mtostr() output format | |
30 | * 2010-12-15: added mcmp() | |
31 | * 2010-12-14: finished mtostr() | |
32 | * 2010-12-12: started models.c | |
33 | */ | |
34 | ||
35 | #include <stdio.h> | |
36 | #include <stdlib.h> | |
37 | #include <string.h> | |
38 | #include "reveng.h" | |
39 | ||
40 | /* Private declarations */ | |
41 | ||
42 | static const poly_t pzero = PZERO; | |
43 | ||
44 | /* Definitions */ | |
45 | ||
46 | void | |
47 | mcpy(model_t *dest, const model_t *src) { | |
48 | /* Copies the parameters of src to dest. | |
49 | * dest must be an initialised model. | |
50 | */ | |
51 | if(!dest || !src) return; | |
52 | pcpy(&dest->spoly, src->spoly); | |
53 | pcpy(&dest->init, src->init); | |
54 | pcpy(&dest->xorout, src->xorout); | |
55 | pcpy(&dest->check, src->check); | |
56 | dest->flags = src->flags; | |
57 | /* link to the name as it is static */ | |
58 | dest->name = src->name; | |
59 | } | |
60 | ||
61 | void | |
62 | mfree(model_t *model) { | |
63 | /* Frees the parameters of model. */ | |
64 | if(!model) return; | |
65 | pfree(&model->spoly); | |
66 | pfree(&model->init); | |
67 | pfree(&model->xorout); | |
68 | pfree(&model->check); | |
69 | /* not name as it is static */ | |
70 | /* not model either, it might point to an array! */ | |
71 | } | |
72 | ||
73 | int | |
74 | mcmp(const model_t *a, const model_t *b) { | |
75 | /* Compares a and b for identical effect, i.e. disregarding | |
76 | * trailing zeroes in parameter polys. | |
77 | * Intended for bsearch(). | |
78 | */ | |
79 | int result; | |
80 | if(!a || !b) return(!b - !a); | |
81 | if((result = psncmp(&a->spoly, &b->spoly))) return(result); | |
82 | if((result = psncmp(&a->init, &b->init))) return(result); | |
83 | if((a->flags & P_REFIN) && (~b->flags & P_REFIN)) return(1); | |
84 | if((~a->flags & P_REFIN) && (b->flags & P_REFIN)) return(-1); | |
85 | if((a->flags & P_REFOUT) && (~b->flags & P_REFOUT)) return(1); | |
86 | if((~a->flags & P_REFOUT) && (b->flags & P_REFOUT)) return(-1); | |
87 | return(psncmp(&a->xorout, &b->xorout)); | |
88 | } | |
89 | ||
90 | char * | |
91 | mtostr(const model_t *model) { | |
92 | /* Returns a malloc()-ed string containing a Williams model | |
93 | * record representing the input model. | |
94 | * mcanon() should be called on the argument before printing. | |
95 | */ | |
96 | size_t size; | |
97 | char *polystr, *initstr, *xorotstr, *checkstr, strbuf[512], *string = NULL; | |
98 | ||
99 | if(!model) return(NULL); | |
100 | polystr = ptostr(model->spoly, P_RTJUST, 4); | |
101 | initstr = ptostr(model->init, P_RTJUST, 4); | |
102 | xorotstr = ptostr(model->xorout, P_RTJUST, 4); | |
103 | checkstr = ptostr(model->check, P_RTJUST, 4); | |
104 | ||
105 | sprintf(strbuf, "%lu", plen(model->spoly)); | |
106 | size = | |
107 | 70 | |
108 | + (model->name && *model->name ? 2 + strlen(model->name) : 6) | |
109 | + strlen(strbuf) | |
110 | + (polystr && *polystr ? strlen(polystr) : 6) | |
111 | + (initstr && *initstr ? strlen(initstr) : 6) | |
112 | + (model->flags & P_REFIN ? 4 : 5) | |
113 | + (model->flags & P_REFOUT ? 4 : 5) | |
114 | + (xorotstr && *xorotstr ? strlen(xorotstr) : 6) | |
115 | + (checkstr && *checkstr ? strlen(checkstr) : 6); | |
116 | if((string = malloc(size))) { | |
117 | sprintf(strbuf, "\"%s\"", model->name); | |
118 | sprintf(string, | |
119 | "width=%lu " | |
120 | "poly=0x%s " | |
121 | "init=0x%s " | |
122 | "refin=%s " | |
123 | "refout=%s " | |
124 | "xorout=0x%s " | |
125 | "check=0x%s " | |
126 | "name=%s", | |
127 | plen(model->spoly), | |
128 | polystr && *polystr ? polystr : "(none)", | |
129 | initstr && *initstr ? initstr : "(none)", | |
130 | (model->flags & P_REFIN) ? "true" : "false", | |
131 | (model->flags & P_REFOUT) ? "true" : "false", | |
132 | xorotstr && *xorotstr ? xorotstr : "(none)", | |
133 | checkstr && *checkstr ? checkstr : "(none)", | |
134 | (model->name && *model->name) ? strbuf : "(none)"); | |
135 | } | |
136 | free(polystr); | |
137 | free(initstr); | |
138 | free(xorotstr); | |
139 | free(checkstr); | |
140 | if(!string) | |
141 | uerror("cannot allocate memory for model description"); | |
142 | return(string); | |
143 | } | |
144 | ||
145 | void | |
146 | mcanon(model_t *model) { | |
147 | /* canonicalise a model */ | |
148 | unsigned long dlen; | |
149 | ||
150 | if(!model) return; | |
151 | ||
152 | /* extending on the right here. This preserves the functionality | |
153 | * of a presumed working model. | |
154 | */ | |
155 | psnorm(&model->spoly); | |
156 | dlen = plen(model->spoly); | |
157 | praloc(&model->init, dlen); | |
158 | praloc(&model->xorout, dlen); | |
159 | ||
160 | /* only calculate Check if missing. Relying on all functions | |
161 | * changing parameters to call mnovel(). This is to ensure that | |
162 | * the Check value stored in the preset table is printed when | |
163 | * the model is dumped. If something goes wrong with the | |
164 | * calculator then the discrepancy with the stored Check value | |
165 | * might be noticed. Storing the Check value with each preset | |
166 | * is highly preferred. | |
167 | */ | |
168 | if(!plen(model->check)) | |
169 | mcheck(model); | |
170 | } | |
171 | ||
172 | void | |
173 | mcheck(model_t *model) { | |
174 | /* calculate a check for the model */ | |
175 | poly_t checkstr, check; | |
176 | ||
177 | /* generate the check string with the correct bit order */ | |
178 | checkstr = strtop("313233343536373839", model->flags, 8); | |
179 | check = pcrc(checkstr, model->spoly, model->init, pzero, model->flags); | |
180 | if(model->flags & P_REFOUT) | |
181 | prev(&check); | |
182 | psum(&check, model->xorout, 0UL); | |
183 | model->check = check; | |
184 | pfree(&checkstr); | |
185 | } | |
186 | ||
187 | void | |
188 | mrev(model_t *model) { | |
189 | /* reverse the model to calculate reversed CRCs */ | |
190 | /* Here we invert RefIn and RefOut so that the user need only | |
191 | * reverse the order of characters in the arguments, not the | |
192 | * characters themselves. If RefOut=True, the mirror image of | |
193 | * Init seen through RefOut becomes XorOut, and as RefOut | |
194 | * becomes false, the XorOut value moved to Init stays upright. | |
195 | * If RefOut=False, Init transfers to XorOut without reflection | |
196 | * but the new Init must be reflected to present the same image, | |
197 | * as RefOut becomes true. | |
198 | */ | |
199 | poly_t temp; | |
200 | ||
201 | prcp(&model->spoly); | |
202 | if(model->flags & P_REFOUT) | |
203 | prev(&model->init); | |
204 | else | |
205 | prev(&model->xorout); | |
206 | ||
207 | /* exchange init and xorout */ | |
208 | temp = model->init; | |
209 | model->init = model->xorout; | |
210 | model->xorout = temp; | |
211 | ||
212 | /* invert refin and refout */ | |
213 | model->flags ^= P_REFIN | P_REFOUT; | |
214 | ||
215 | mnovel(model); | |
216 | } | |
217 | ||
218 | void | |
219 | mnovel(model_t *model) { | |
220 | /* remove name and check string from modified model */ | |
221 | model->name = NULL; | |
222 | pfree(&model->check); | |
223 | } |