#include "scanner_setting.h" #include #include #include /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // DEFINE ... #define SSFH_VER_MAIN 1 #define SSFH_VER_MINOR 0 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // base64 util .. static char base64_default_table[] = { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" }; base64::base64() : padding_char_('=') { base64_ind_[0] = base64_char_[0] = 0; initialize_base64_table(base64_default_table); } base64::~base64() {} bool base64::is_valid_base64_table(const char* table) { bool valid = false; if (table && strlen(table) >= 64) { char repeat[4] = { 0 }; valid = true; for (int i = 0; i < 63; ++i) { repeat[0] = table[i]; if (strstr(table + i + 1, repeat)) { valid = false; break; } } } return valid; } bool base64::initialize_base64_table(const char* table) { if (!table || strlen(table) < 64) { if (memcmp(base64_default_table, base64_char_, 64) == 0) { return !table; } memcpy(base64_char_, base64_default_table, 64); } else { if (memcmp(base64_char_, table, 64) == 0) { return true; } else if (!is_valid_base64_table(table)) return false; memcpy(base64_char_, table, 64); } base64_char_[64] = base64_char_[65] = 0; // initialize base64_index memset(base64_ind_, 0, sizeof(base64_ind_)); for (int i = 0; i < 64; ++i) { base64_ind_[base64_char_[i]] = i; } // padding char padding_char_ = '='; if (base64_ind_[padding_char_]) { for (padding_char_ = 0x21; padding_char_ < 0x7e && base64_ind_[padding_char_] && padding_char_ != base64_char_[0]; ++padding_char_); } return padding_char_ < 0x7e; } bool base64::set_base64_table(const char* table) { return initialize_base64_table(table ? table : base64_default_table); } std::string base64::encode(const char* data, size_t bytes, unsigned int line_bytes, bool need_padding) { char* str = (char*)malloc(bytes * 2 + 3); unsigned char c1 = 0, c2 = 0, c3 = 0; unsigned long line_len = 0; unsigned long words = bytes / 3; int rest = bytes % 3, pos = 0; std::string ret(""); for (unsigned long i = 0; i < words; ++i) { // fetch 3 letters c1 = *data++; c2 = *data++; c3 = *data++; // encoding into 4-bytes str[pos++] = base64_char_[c1 >> 2]; str[pos++] = base64_char_[((c1 << 4) | (c2 >> 4)) & 0x3f]; str[pos++] = base64_char_[((c2 << 2) | (c3 >> 6)) & 0x3f]; str[pos++] = base64_char_[c3 & 0x3f]; line_len += 4; // new line ... if ((unsigned int)line_len > line_bytes - 4) { str[pos++] = '\r'; str[pos++] = '\n'; line_len = 0; } } // rest ... if (rest == 1) { c1 = *data++; str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; str[pos++] = base64_char_[((c1 & 0x03) << 4)]; if (need_padding) { str[pos++] = padding_char_; str[pos++] = padding_char_; } } else if (rest == 2) { c1 = *data++; c2 = *data++; str[pos++] = base64_char_[(c1 & 0xfc) >> 2]; str[pos++] = base64_char_[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; str[pos++] = base64_char_[((c2 & 0x0f) << 2)]; if (need_padding) { str[pos++] = padding_char_; } } if (pos > 0) { str[pos++] = 0; ret = std::string(str, pos - 1); } free(str); return ret; } std::string base64::decode(const char* data, size_t bytes) { char* str = (char*)malloc(bytes + 1); int pos = 0, shifts = 18, value = 0; std::string ret(""); for (int i = 0; i < (int)bytes; ++i) { if (*data != '\r' && *data != '\n') { if (*data == padding_char_) { break; } value += base64_ind_[*data] << shifts; if (shifts == 0) { shifts = 18; str[pos++] = (value >> 16) & 0x0ff; str[pos++] = (value >> 8) & 0x0ff; str[pos++] = (value >> 0) & 0x0ff; value = 0; } else { shifts -= 6; } } data++; } if (shifts == 12 || shifts == 6) { str[pos++] = (value >> 16) & 0x0ff; } else if (shifts == 0) { str[pos++] = (value >> 16) & 0x0ff; str[pos++] = (value >> 8) & 0x0ff; } if (pos > 0) { str[pos++] = 0; ret = std::string(str, pos - 1); } free(str); return ret; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // check sum .. unsigned int simple_checksum(const char* data, size_t len) { unsigned int chk = -1; while (len >= sizeof(chk)) { chk ^= *((unsigned int*)data); data += sizeof(chk); len -= sizeof(chk); } if (len) { unsigned int rest = *((unsigned int*)data), mask = (1 << (len * 8)) - 1; rest &= mask; chk ^= rest; } return chk; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // exporting .. int load_scanner_setting(const char* file, std::string& jsn) { FILE* src = fopen(file, "rb"); long len = 0; char* buf = nullptr; SSFILEH ssfh = { 0 }; if (!src) return errno; fseek(src, 0, SEEK_END); len = ftell(src); fseek(src, 0, SEEK_SET); if (len < sizeof(ssfh)) { fclose(src); return EBADF; } buf = new char[len]; if (!buf) { fclose(src); return ENOMEM; } memset(buf, 0, len); fread(&ssfh, sizeof(ssfh), 1, src); len -= sizeof(ssfh); fread(buf, 1, len, src); fclose(src); if (ssfh.ver_main != 1 || ssfh.ver_sub != 0 || simple_checksum(buf, len) != (ssfh.checksum ^ ssfh.timestamp) || ssfh.length != len + sizeof(ssfh)) { delete[] buf; return EBADF; } base64 b64; jsn = b64.decode(buf, len); delete[] buf; return 0; } int save_scanner_setting(const char* file, const std::string& jsn) { SSFILEH ssfh = { 0 }; base64 b64; std::string str(b64.encode(jsn.c_str(), jsn.length())); ssfh.ver_main = SSFH_VER_MAIN; ssfh.ver_sub = SSFH_VER_MINOR; ssfh.length = str.length() + sizeof(ssfh); ssfh.timestamp = time(NULL); ssfh.checksum = simple_checksum(str.c_str(), str.length()); FILE *dst = fopen(file, "wb"); bool ok = false; if (!dst) return ENFILE; ssfh.checksum ^= ssfh.timestamp; if (fwrite(&ssfh, sizeof(ssfh), 1, dst) == 1) ok = fwrite(str.c_str(), 1, str.length(), dst) == str.length(); fclose(dst); if (!ok) { remove(file); return EFAULT; } return 0; }