io_cube.h (8251B)
1 STATIC cube_t readcube(const char *, const char *); 2 STATIC int64_t writecube(const char *, cube_t, uint64_t, char *); 3 STATIC void log_available_formats(void); 4 STATIC uint8_t readco(const char *); 5 STATIC uint8_t readcp(const char *); 6 STATIC uint8_t readeo(const char *); 7 STATIC uint8_t readep(const char *); 8 STATIC cube_t readcube_B32(const char *); 9 STATIC cube_t readcube_H48(const char *); 10 STATIC uint8_t readpiece_LST(const char **); 11 STATIC cube_t readcube_LST(const char *); 12 13 STATIC int64_t writepiece_LST(uint8_t, uint64_t, char *); 14 STATIC int64_t writecube_B32(cube_t, uint64_t, char *); 15 STATIC int64_t writecube_H48(cube_t, uint64_t, char *); 16 STATIC int64_t writecube_LST(cube_t, uint64_t, char *); 17 18 STATIC uint8_t b32toedge(char); 19 STATIC uint8_t b32tocorner(char); 20 STATIC char edgetob32(uint8_t); 21 STATIC char cornertob32(uint8_t); 22 23 STATIC struct { 24 const char *name; 25 cube_t (*read)(const char *); 26 int64_t (*write)(cube_t, uint64_t, char *); 27 } ioformat[] = 28 { 29 { .name = "B32", .read = readcube_B32, .write = writecube_B32 }, 30 { .name = "LST", .read = readcube_LST, .write = writecube_LST }, 31 { .name = "H48", .read = readcube_H48, .write = writecube_H48 }, 32 { .name = "NONE", .read = NULL, .write = NULL }, 33 }; 34 35 STATIC cube_t 36 readcube(const char *format, const char *buf) 37 { 38 int i; 39 40 for (i = 0; ioformat[i].read != NULL; i++) 41 if (!strcmp(format, ioformat[i].name)) 42 return ioformat[i].read(buf); 43 44 LOG("Cannot read cube: unknown format '%s'\n", format); 45 log_available_formats(); 46 return ZERO_CUBE; 47 } 48 49 STATIC int64_t 50 writecube(const char *format, cube_t cube, uint64_t buf_size, char *buf) 51 { 52 int i; 53 54 for (i = 0; ioformat[i].write != NULL; i++) 55 if (!strcmp(format, ioformat[i].name)) 56 return ioformat[i].write(cube, buf_size, buf); 57 58 LOG("Cannot write cube: unknown format '%s'\n", format); 59 log_available_formats(); 60 return NISSY_ERROR_INVALID_FORMAT; 61 } 62 63 STATIC void 64 log_available_formats(void) 65 { 66 int i; 67 68 LOG("Available formats: "); 69 for (i = 0; ioformat[i].read != NULL; i++) 70 LOG("'%s' ", ioformat[i].name); 71 LOG("\n"); 72 } 73 74 STATIC uint8_t 75 readco(const char *str) 76 { 77 if (*str == '0') 78 return 0; 79 if (*str == '1') 80 return CTWIST_CW; 81 if (*str == '2') 82 return CTWIST_CCW; 83 84 LOG("Error reading CO\n"); 85 return UINT8_ERROR; 86 } 87 88 STATIC uint8_t 89 readcp(const char *str) 90 { 91 uint8_t c; 92 93 for (c = 0; c < 8; c++) 94 if (!strncmp(str, cornerstr[c], 3) || 95 !strncmp(str, cornerstralt[c], 3)) 96 return c; 97 98 LOG("Error reading CP\n"); 99 return UINT8_ERROR; 100 } 101 102 STATIC uint8_t 103 readeo(const char *str) 104 { 105 if (*str == '0') 106 return 0; 107 if (*str == '1') 108 return EFLIP; 109 110 LOG("Error reading EO\n"); 111 return UINT8_ERROR; 112 } 113 114 STATIC uint8_t 115 readep(const char *str) 116 { 117 uint8_t e; 118 119 for (e = 0; e < 12; e++) 120 if (!strncmp(str, edgestr[e], 2)) 121 return e; 122 123 LOG("Error reading EP\n"); 124 return UINT8_ERROR; 125 } 126 127 STATIC cube_t 128 readcube_B32(const char *buf) 129 { 130 int i; 131 uint8_t c[8], e[12]; 132 133 for (i = 0; i < 8; i++) { 134 c[i] = b32tocorner(buf[i]); 135 if (c[i] == UINT8_ERROR) { 136 LOG("Error reading B32 corner %d ", i); 137 if (buf[i] == 0) { 138 LOG("(string terminated early)\n"); 139 } else { 140 LOG("(char '%c')\n", buf[i]); 141 } 142 return ZERO_CUBE; 143 } 144 } 145 146 if (buf[8] != '=') { 147 LOG("Error reading B32 separator: a single '=' " 148 "must be used to separate edges and corners\n"); 149 return ZERO_CUBE; 150 } 151 152 for (i = 0; i < 12; i++) { 153 e[i] = b32toedge(buf[i+9]); 154 if (e[i] == UINT8_ERROR) { 155 LOG("Error reading B32 edge %d ", i); 156 if (buf[i+9] == 0) { 157 LOG("(string terminated early)\n"); 158 } else { 159 LOG("(char '%c')\n", buf[i+9]); 160 } 161 return ZERO_CUBE; 162 } 163 } 164 165 return cubefromarray(c, e); 166 } 167 168 STATIC cube_t 169 readcube_H48(const char *buf) 170 { 171 int i; 172 uint8_t piece, orient, c[8], e[12]; 173 const char *b; 174 175 b = buf; 176 177 for (i = 0; i < 12; i++) { 178 while (*b == ' ' || *b == '\t' || *b == '\n') 179 b++; 180 if ((piece = readep(b)) == UINT8_ERROR) 181 return ZERO_CUBE; 182 b += 2; 183 if ((orient = readeo(b)) == UINT8_ERROR) 184 return ZERO_CUBE; 185 b++; 186 e[i] = piece | orient; 187 } 188 for (i = 0; i < 8; i++) { 189 while (*b == ' ' || *b == '\t' || *b == '\n') 190 b++; 191 if ((piece = readcp(b)) == UINT8_ERROR) 192 return ZERO_CUBE; 193 b += 3; 194 if ((orient = readco(b)) == UINT8_ERROR) 195 return ZERO_CUBE; 196 b++; 197 c[i] = piece | orient; 198 } 199 200 return cubefromarray(c, e); 201 } 202 203 STATIC uint8_t 204 readpiece_LST(const char **b) 205 { 206 uint8_t ret; 207 bool read; 208 209 while (**b == ',' || **b == ' ' || **b == '\t' || **b == '\n') 210 (*b)++; 211 212 for (ret = 0, read = false; **b >= '0' && **b <= '9'; (*b)++) { 213 read = true; 214 ret = ret * 10 + (**b) - '0'; 215 } 216 217 return read ? ret : UINT8_ERROR; 218 } 219 220 STATIC cube_t 221 readcube_LST(const char *buf) 222 { 223 int i; 224 uint8_t c[8], e[12]; 225 226 for (i = 0; i < 8; i++) 227 c[i] = readpiece_LST(&buf); 228 229 for (i = 0; i < 12; i++) 230 e[i] = readpiece_LST(&buf); 231 232 return cubefromarray(c, e); 233 } 234 235 STATIC int64_t 236 writepiece_LST(uint8_t piece, uint64_t buf_size, char *buf) 237 { 238 char digits[3]; 239 uint64_t i, len; 240 241 if (piece > 99 || buf_size < 3) 242 return 0; 243 244 len = 0; 245 while (piece != 0) { 246 digits[len++] = (piece % 10) + '0'; 247 piece /= 10; 248 } 249 250 if (buf_size < len+2) 251 return 0; 252 253 if (len == 0) 254 digits[len++] = '0'; 255 256 for (i = 0; i < len; i++) 257 buf[i] = digits[len-i-1]; 258 259 buf[len] = ','; 260 buf[len+1] = ' '; 261 262 return len+2; 263 } 264 265 STATIC int64_t 266 writecube_B32(cube_t cube, uint64_t buf_size, char *buf) 267 { 268 int i; 269 uint8_t corner[8], edge[12]; 270 271 if (buf_size < NISSY_SIZE_B32) { 272 LOG("Cannot write cube in B32 format: buffer size must be " 273 "at least %" PRIu64 " bytes, but the provided one is %" 274 PRIu64 " bytes.\n", NISSY_SIZE_B32, buf_size); 275 return NISSY_ERROR_BUFFER_SIZE; 276 } 277 278 pieces(&cube, corner, edge); 279 280 for (i = 0; i < 8; i++) 281 buf[i] = cornertob32(corner[i]); 282 283 buf[8] = '='; 284 285 for (i = 0; i < 12; i++) 286 buf[i+9] = edgetob32(edge[i]); 287 288 buf[21] = '\0'; 289 290 return NISSY_OK; 291 } 292 293 STATIC int64_t 294 writecube_H48(cube_t cube, uint64_t buf_size, char *buf) 295 { 296 uint8_t piece, perm, orient, corner[8], edge[12]; 297 int i; 298 299 if (buf_size < NISSY_SIZE_H48) { 300 LOG("Cannot write cube in H48 format: buffer size must be " 301 "at least %" PRIu64 " bytes, but the provided one is %" 302 PRIu64 " bytes.\n", NISSY_SIZE_H48, buf_size); 303 return NISSY_ERROR_BUFFER_SIZE; 304 } 305 306 pieces(&cube, corner, edge); 307 308 for (i = 0; i < 12; i++) { 309 piece = edge[i]; 310 perm = piece & PBITS; 311 orient = (piece & EOBIT) >> EOSHIFT; 312 buf[4*i ] = edgestr[perm][0]; 313 buf[4*i + 1] = edgestr[perm][1]; 314 buf[4*i + 2] = orient + '0'; 315 buf[4*i + 3] = ' '; 316 } 317 for (i = 0; i < 8; i++) { 318 piece = corner[i]; 319 perm = piece & PBITS; 320 orient = (piece & COBITS) >> COSHIFT; 321 buf[48 + 5*i ] = cornerstr[perm][0]; 322 buf[48 + 5*i + 1] = cornerstr[perm][1]; 323 buf[48 + 5*i + 2] = cornerstr[perm][2]; 324 buf[48 + 5*i + 3] = orient + '0'; 325 buf[48 + 5*i + 4] = ' '; 326 } 327 328 buf[48+39] = '\0'; 329 330 return NISSY_OK; 331 } 332 333 STATIC int64_t 334 writecube_LST(cube_t cube, uint64_t buf_size, char *buf) 335 { 336 int i; 337 uint64_t ptr; 338 uint8_t piece, corner[8], edge[12]; 339 340 ptr = 0; 341 pieces(&cube, corner, edge); 342 343 for (i = 0; i < 8; i++) { 344 piece = corner[i]; 345 ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); 346 if (ptr == 0) 347 goto writecube_LST_error; 348 } 349 350 for (i = 0; i < 12; i++) { 351 piece = edge[i]; 352 ptr += writepiece_LST(piece, buf_size - ptr, buf + ptr); 353 if (ptr == 0) 354 goto writecube_LST_error; 355 } 356 357 *(buf+ptr-2) = '\0'; 358 359 return NISSY_OK; 360 361 writecube_LST_error: 362 LOG("Cannot write cube in LST: buffer is too small (%" PRIu64 363 " bytes given). The LST format has a variable size, try a " 364 "larger buffer.\n", buf_size); 365 return NISSY_ERROR_BUFFER_SIZE; 366 } 367 368 STATIC uint8_t 369 b32toedge(char c) 370 { 371 if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) 372 return UINT8_ERROR; 373 374 return c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; 375 } 376 377 STATIC uint8_t 378 b32tocorner(char c) { 379 uint8_t val; 380 381 if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'f'))) 382 return UINT8_ERROR; 383 384 val = c <= 'Z' ? (uint8_t)(c - 'A') : (uint8_t)(c - 'a') + 26; 385 386 return (val & 7) | ((val & 24) << 2); 387 } 388 389 STATIC char 390 edgetob32(uint8_t edge) 391 { 392 return edge < 26 ? 'A' + (char)edge : 'a' + (char)(edge - 26); 393 } 394 395 STATIC char 396 cornertob32(uint8_t corner) 397 { 398 uint8_t val; 399 400 val = (corner & 7) | ((corner & 96) >> 2); 401 402 return val < 26 ? 'A' + (char)val : 'a' + (char)(val - 26); 403 }