/* * scribiu -- read notebooks and voice memos from Livescribe pens * Copyright (C) 2015 Javier S. Pedro * * This file contains parts of: * libsmartpen -- library for communicating with the Livescribe Pulse Smartpen * Copyright (C) 2010 Steven Walter * * 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 3 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include "stfreader.h" #define TABLE_v(i, ...) static qint8 tab_ ## i [] = { __VA_ARGS__ } #define TABLE static CodeTable table[] = { #define TABLE_i(i) {i, sizeof(tab_ ## i), tab_ ## i}, #define END_TABLE }; static int table_size = sizeof(table) / sizeof(CodeTable); StfReader::StfReader() : handler(0) { } StfReader::~StfReader() { } StfReader::StrokeHandler::~StrokeHandler() { } bool StfReader::parseV1(BitReader& br) { quint64 cur_time = 0; while (!br.atEnd()) { syncV1(br); quint8 header = br.readBits(8); quint64 time; QPoint p0, pa; int f0; switch (header) { case 0x80: /* End of file. */ return true; break; case 0: time = br.readBits(8); break; case 0x08: time = br.readBits(16); break; case 0x10: time = br.readBits(32); break; case 0x18: time = br.readBits(64); break; default: qWarning("Unknown header 0x%x", header); return false; } /* Start of a stroke. */ cur_time += time; p0.setX(br.readBits(16)); p0.setY(br.readBits(16)); f0 = readForce(br); quint64 stroke_time = cur_time; if (handler) { bool res = handler->startStroke(p0, f0, cur_time); if (!res) return false; } while (!br.atEnd()) { header = readHeader(br); if (header == 0 || header == 1) { time = readTime(br); } else { int header2 = readHeader2(br); switch (header2) { case 0: time = br.readBits(8); break; case 1: time = br.readBits(16); break; case 2: time = br.readBits(32); break; default: qWarning("Unknown stroke time header %d", header2); return false; } } if (time == 0) { if (handler) { bool res = handler->endStroke(stroke_time); if (!res) return false; } break; } bool do_delta; QPoint delta; qint8 deltaf; if (header > 0) { bool have_len = br.readBits(1); if (have_len) { do_delta = false; QPoint p1; p1.setX(br.readBits(16)); p1.setY(br.readBits(16)); pa = p1 - p0; } else { do_delta = true; delta.setX(br.readSignedBits(8)); delta.setY(br.readSignedBits(8)); } } else { do_delta = true; delta.setX(readDeltaX(br)); delta.setY(readDeltaY(br)); } deltaf = readDeltaF(br); if (do_delta) { pa = delta + (pa * static_cast(time)) / 256; } p0 += pa; pa *= 256 / static_cast(time); f0 += deltaf; stroke_time += time; if (handler) { bool res = handler->strokePoint(p0, f0, stroke_time); if (!res) return false; } } } return false; } void StfReader::syncV1(BitReader &br) { br.skipUntilNextByte(); while (!br.atEnd() && (br.peekBits(8) & ~(0x80|0x10|0x08))) { br.readBits(8); } } qint8 StfReader::decodeV1(BitReader& br, CodeTable* tab, int tab_size) { int got_bits = 0; int codeacc = 0; int stream = 0; for (int i = 0; i < tab_size; i++) { int get_bits = tab[i].bits - got_bits; codeacc <<= get_bits; codeacc += tab[i].size; stream <<= get_bits; stream |= br.readBits(get_bits); got_bits += get_bits; int idx = stream - codeacc; if (idx < 0) { idx = tab[i].size + idx; Q_ASSERT(idx >= 0 && idx < tab[i].size); return tab[i].data[idx]; } } qWarning("Unknown code"); return 0; } qint8 StfReader::readForce(BitReader &br) { TABLE_v(1, 0); TABLE_v(6, 1,4,7,9,10,11,13,15,17,20,21,22,23,24,25,26,27,28,30); TABLE_v(7, 2,3,5,6,8,12,14,16,18,19,29,31,32,33,34,35,36,49,52); TABLE_v(8, 37,45,46,47,48,50,51,53,54); TABLE_v(9, 38,39,40,41,44,55,56); TABLE_v(10, 43,57,58); TABLE_v(11, 42,59,60,61,62,63); TABLE TABLE_i(1) TABLE_i(6) TABLE_i(7) TABLE_i(8) TABLE_i(9) TABLE_i(10) TABLE_i(11) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readHeader(BitReader &br) { TABLE_v(1, 0); TABLE_v(2, 1, 2); TABLE TABLE_i(1) TABLE_i(2) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readHeader2(BitReader &br) { TABLE_v(1, 0); TABLE_v(2, 1, 3); TABLE TABLE_i(1) TABLE_i(2) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readHeader3(BitReader &br) { TABLE_v(1, 0,1); TABLE TABLE_i(1) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readTime(BitReader &br) { TABLE_v(1, 1); TABLE_v(2, 2); TABLE_v(4, 0,3,4); TABLE_v(6, 5,6); TABLE_v(7, 7,8); TABLE_v(8, 9); TABLE_v(9, 10,11); TABLE_v(10, 12,13,14); TABLE_v(11, 15); TABLE_v(12, 16,17,18,19,21,22); TABLE_v(13, 20,23,24,25,26,27); TABLE_v(14, 28,29,30,31,32,35,36,37,40); TABLE_v(15, 38,39,41,44,45,48,50,53,59,60,67,73,82,91,98,99,102); TABLE_v(16, 33,34,42,43,46,47,49,51,52,54,55,56,57,58,61,62,63,64,65,66,68,69,70,71,72,74,75,76,77,78,79,80,81,83,84,85,86,87,88,89,90,92,93,94,95,96,97,100,101,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127); TABLE TABLE_i(1) TABLE_i(2) TABLE_i(4) TABLE_i(6) TABLE_i(7) TABLE_i(8) TABLE_i(9) TABLE_i(10) TABLE_i(11) TABLE_i(12) TABLE_i(13) TABLE_i(14) TABLE_i(15) TABLE_i(16) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readDeltaX(BitReader &br) { TABLE_v(4, 3,4,5); TABLE_v(5, 0,1,2,6,7,8,9,-8,-7,-6,-5,-4,-3,-2,-1); TABLE_v(6, 10,11,12,13,-13,-12,-11,-10,-9); TABLE_v(7, 14,15,16,17,18,19,-18,-17,-16,-15,-14); TABLE_v(8, 20,21,22,23,24,26,-25,-24,-23,-22,-21,-20,-19); TABLE_v(9, 25,27,28,29,30,31,32,33,34,36,38,-36,-34,-33,-32,-31,-30,-29,-28,-27,-26); TABLE_v(10, 35,37,39,40,41,42,43,44,45,46,47,49,55,-57,-50,-47,-46,-44,-43,-42,-41,-40,-39,-38,-37,-35); TABLE TABLE_i(4) TABLE_i(5) TABLE_i(6) TABLE_i(7) TABLE_i(8) TABLE_i(9) TABLE_i(10) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readDeltaY(BitReader &br) { TABLE_v(5, 0,1,2,3,4,5,6,7,8,-9,-8,-7,-6,-5,-4,-3,-2,-1); TABLE_v(6, 9,10,11,12,13,-14,-13,-12,-11,-10); TABLE_v(7, 14,15,16,17,18,19,20,-20,-19,-18,-17,-16,-15); TABLE_v(8, 21,22,23,24,25,26,27,28,29,30,31,-27,-26,-25,-24,-23,-22,-21); TABLE_v(9, 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,49,-45,-44,-43,-40,-39,-38,-37,-36,-35,-34,-33,-32,-31,-30,-29,-28); TABLE_v(10, 47,48,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,66,67,68,69,71,72,73,78,85,-75,-69,-64,-62,-61,-60,-59,-58,-57,-56,-55,-54,-53,-52,-51,-50,-49,-48,-47,-46,-42,-41); TABLE TABLE_i(5) TABLE_i(6) TABLE_i(7) TABLE_i(8) TABLE_i(9) TABLE_i(10) END_TABLE return decodeV1(br, table, table_size); } qint8 StfReader::readDeltaF(BitReader &br) { TABLE_v(1, 0); TABLE_v(3, 1); TABLE_v(4, -1); TABLE_v(5, 2,-2); TABLE_v(6, 3,-3); TABLE_v(7, 4,52,53,-4); TABLE_v(8, 5,6,49,50,51,54,55,-17,-16,-15,-14,-13,-12,-7,-6,-5); TABLE_v(9, 7,8,9,10,11,12,13,30,31,36,37,38,39,40,41,46,48,56,57,-56,-55,-54,-53,-52,-51,-50,-49,-40,-38,-21,-20,-19,-18,-11,-10,-9,-8); TABLE_v(10, 14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,32,33,34,35,42,43,44,45,47,58,-57,-48,-47,-46,-45,-44,-43,-42,-41,-39,-37,-36,-35,-34,-33,-32,-31,-29,-28,-27,-26,-25,-24,-23,-22); TABLE_v(11, -59,-58,-30); TABLE_v(12, 59,-64); TABLE_v(13, 60,61,62,63,-63,-62,-61,-60); TABLE TABLE_i(1) TABLE_i(3) TABLE_i(4) TABLE_i(5) TABLE_i(6) TABLE_i(7) TABLE_i(8) TABLE_i(9) TABLE_i(10) TABLE_i(11) TABLE_i(12) TABLE_i(13) END_TABLE return decodeV1(br, table, table_size); } bool StfReader::parse(QIODevice *device) { char magic; if (!device->getChar(&magic)) return false; if (magic != 0x1) return false; if (!device->getChar(&magic)) return false; if (magic != 0x0) return false; QString version(device->read(14)); if (version != "Anoto STF v1.0") { return false; } BitReader br(device); speed = br.readBits(16); return parseV1(br); } bool StfReader::parse(const QString &filename) { QFile f(filename); if (!f.open(QIODevice::ReadOnly)) { qWarning() << "Could not open" << f.fileName(); } return parse(&f); } void StfReader::setStrokeHandler(StrokeHandler *newHandler) { Q_ASSERT(newHandler); handler = newHandler; }