/* * Copyright 2007 Michael Buckley * * 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 Public License for more * details. * * You should have received a copy of the GNU General Public License along * with this program; if not, If not, see . */ #include #include #include #include #include #ifdef MINGW #include #endif #include "brnconvert.h" uint32_t traverseMegahalTree(uint8_t* brain, long start, long bound); long getMegahalDictStart(uint8_t* brain, long brainLen); void flipMegahalBrain(uint8_t* brain, long brainLen, long dictStart); void flip16InPlace(uint8_t* x); void flip32InPlace(uint8_t* x); int convertMegahalBrain(uint8_t* brain, long brainLen, megahal_filetype target) { #if !BYTE_ORDER == BIG_ENDIAN && !BYTE_ORDER == LITTLE_ENDIAN return MEGAHAL_UNSUPPORTED_ENDIANESS; #endif if(brain[9] != 5){ return MEGAHAL_UNKNOWN_INPUT; } char cookie[10]; memset(cookie, 0, 10); memcpy(cookie, brain, 9); if(strcmp(cookie, "MegaHALv8") != 0){ return MEGAHAL_UNKNOWN_INPUT; } megahal_filetype type = MEGAHAL_UNKNOWN_FILETYPE; long dictStart = getMegahalDictStart(brain, brainLen); if(dictStart <= 0){ return MEGAHAL_UNKNOWN_INPUT; } /* Determine endianess of the input */ uint32_t dictLength; memcpy(&dictLength, brain + dictStart, 4); uint32_t flippedDictLength = dictLength; flip32InPlace((uint8_t*) &flippedDictLength); if(dictLength != flippedDictLength){ long i = dictStart + 4; uint32_t numWords = 0; uint8_t wordLen = 0; while(i < brainLen){ wordLen = brain[i]; ++numWords; i += wordLen + 1; } if(numWords == dictLength){ #if BYTE_ORDER == BIG_ENDIAN type = MEGAHAL_BIG_ENDIAN; #elif BYTE_ORDER == LITTLE_ENDIAN type = MEGAHAL_LITTLE_ENDIAN; #endif }else if(numWords == flippedDictLength){ #if BYTE_ORDER == BIG_ENDIAN type = MEGAHAL_LITTLE_ENDIAN; #elif BYTE_ORDER == LITTLE_ENDIAN type = MEGAHAL_BIG_ENDIAN; #endif } }else{ /* This is a rare occurance, so go out of your way to test it. */ long position = traverseMegahalTree(brain, 10, dictStart); if(position >= 0){ position = traverseMegahalTree(brain, position, dictStart); if(position >= 0){ if(position == dictStart){ /* Not a 100% guarantee, but very unlikely to be * incorrect in the real world. */ #if BYTE_ORDER == BIG_ENDIAN type = MEGAHAL_BIG_ENDIAN; #elif BYTE_ORDER == LITTLE_ENDIAN type = MEGAHAL_LITTLE_ENDIAN; #endif }else{ #if BYTE_ORDER == BIG_ENDIAN type = MEGAHAL_LITTLE_ENDIAN; #elif BYTE_ORDER == LITTLE_ENDIAN type = MEGAHAL_BIG_ENDIAN; #endif } } } if(position < 0){ #if BYTE_ORDER == BIG_ENDIAN type = MEGAHAL_LITTLE_ENDIAN; #elif BYTE_ORDER == LITTLE_ENDIAN type = MEGAHAL_BIG_ENDIAN; #endif } } if(type == target){ return 0; }else if(type == MEGAHAL_UNKNOWN_FILETYPE){ return MEGAHAL_UNKNOWN_INPUT; }else{ flipMegahalBrain(brain, brainLen, dictStart); } return 0; } int forceMegahalConversion(uint8_t* brain, long brainLen) { long dictStart = getMegahalDictStart(brain, brainLen); if(dictStart <= 0){ return MEGAHAL_UNKNOWN_INPUT; } flipMegahalBrain(brain, brainLen, dictStart); return 0; } /* This function attempts to traverse a MegaHALv8 tree. If the tree extends past * bound, the function returns -1, otherwise, it returns the position in the * brain of the end of the tree. MegaHALv8 brains have two trees. If the second * ends at the start of the dictionary, than it is extremely likely that the * brain is of the same endianess as the machine executing this function. */ uint32_t traverseMegahalTree(uint8_t* brain, long start, long bound) { if(start + 10 > bound) { return -1; } uint16_t numBranches; memcpy(&numBranches, brain + start + 8, 2); long newStart = start + 10; uint32_t i; for(i = 0; i < numBranches; ++i){ newStart = traverseMegahalTree(brain, newStart, bound); if(newStart < 0){ break; } } return newStart; } /* This function finds the start of the MegaHALv8 dictionary. It takes advantage * of the fact that the dictionary starts with "". */ long getMegahalDictStart(uint8_t* brain, long brainLen) { long dictStart = brainLen; char c = brain[dictStart]; int foundStart = 0; while(foundStart == 0 && dictStart >= 0){ /* Search for the start of the dictionary */ if(c == 7){ char test[8]; memset(test, 0, 8); memcpy(test, &brain[dictStart + 1], 7); if(strcmp(test, "") == 0){ foundStart = 1; } } if(foundStart == 0){ --dictStart; c = brain[dictStart]; } } return dictStart - 4; } /* This function performs the flipping of the MegaHALv8 brain. Since the * dictionary must not be flipped, this function requires the start position * of the dictonary. */ void flipMegahalBrain(uint8_t* brain, long brainLen, long dictStart) { long position = 10; while(position < dictStart){ flip16InPlace(brain + position); flip32InPlace(brain + position + 2); flip16InPlace(brain + position + 6); flip16InPlace(brain + position + 8); position += 10; } flip32InPlace(brain + position); } void flip16InPlace(uint8_t* x) { uint8_t temp = x[0]; x[0] = x[1]; x[1] = temp; } void flip32InPlace(uint8_t* x){ char temp[4]; memcpy(&temp, x, 4); x[0] = temp[3]; x[1] = temp[2]; x[2] = temp[1]; x[3] = temp[0]; }