Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
297e84bedThis file is pinned to the selected release. Download the original to open it in your design tool.
#include "gcode_thumb_decoder.h"
bool SLine::IsBeginThumbnail() const {
static const char thumbnailBegin[] =
"; thumbnail begin "; // pozor na tu mezeru na konci
// pokud zacina radka na ; thumbnail, lze se tim zacit zabyvat
// nemuzu pouzivat zadne pokrocile algoritmy, musim vystacit se strcmp
const char *lc =
(const char *)l; // jen quli debuggeru, abych do toho videl...
// ta -1 na size ma svuj vyznam - chci, aby strncmp NEporovnavalo ten null
// znak na konci, cili abych se nemusel srat s tim, ze vstupni string je
// delsi, cili aby to emulovalo chovani boost::starts_with()
if (!strncmp(lc, thumbnailBegin,
std::min(sizeof(l), sizeof(thumbnailBegin)) - 1)) {
// zacatek thumbnailu
unsigned int x, y;
unsigned long bytes;
lc = lc + sizeof(thumbnailBegin) - 1;
int ss = sscanf(lc, "%ux%u %lu", &x, &y, &bytes);
if (ss == 3) { // 3 uspesne prectene itemy - rozliseni
// je to platny zacatek thumbnailu, je to ten muj?
if (x == 220 && y == 124) {
// je to ten muj, ktery chci
return true;
}
}
}
return false;
}
bool SLine::IsEndThumbnail() const {
static const char thumbnailEnd[] = "; thumbnail end";
// proc -1 viz. vysvetleni v LineIsBeginThumbnail
return !strncmp((const char *)l, thumbnailEnd,
std::min(sizeof(l), sizeof(thumbnailEnd)) - 1);
}
bool GCodeThumbDecoder::ReadByte(FIL *f, uint8_t &byte) {
UINT br = 0;
return f_read(f, &byte, 1, &br) == FR_OK && br == 1;
}
bool GCodeThumbDecoder::ReadLine(FIL *f, SLine &line) {
uint8_t byte;
for (;;) {
if (f_eof(f) || !ReadByte(f, byte))
return false;
if (byte == '\n')
break;
line.AppendByte(byte);
}
return true;
}
bool GCodeThumbDecoder::AppendBase64Chars(
const char *src, GCodeThumbDecoder::TBytesQueue &bytesQ) {
// a tohle uz je i s dekodovanim
while (*src) {
uint8_t bajt;
switch (base64SD.ConsumeChar(*src++, &bajt)) {
case 1:
bytesQ.enqueue(bajt);
break;
case -1:
return false; // chyba v dekodovani
default:
break; // zadny bajt na vystup
}
}
return true;
}
int GCodeThumbDecoder::Read(FIL *f, char *pc, int n) {
static const size_t MAX_READ_LINES = 2048; // treba 2K radek
switch (state) {
case States::Searching: {
// ctu radky, dokud nenarazim na begin thumbnail nebo neprelezu max
// ctenou velikost (radove asi 64KB) nebo neskonci fajl
for (size_t lines = 0; lines < MAX_READ_LINES; ++lines) {
SLine l;
if (!ReadLine(f, l)) {
// tahle podminka nevypada na prvni pohled uplne spravne, ale je
// treba si uvedomit, ze hledany thumbnail rozhodne neni na
// konci fajlu, takze lze s klidem skoncit bez ocheckovani
// posledni nactene radky z fajlu Podobna domain-specific
// prasecina je tu vickrat
state = States::Error;
break; // konec souboru
}
if (l.IsBeginThumbnail()) {
state = States::Base64;
break; // nalezen png meho rozmeru, budu cist jeho data
}
}
if (state != States::Base64) {
// nenalezen png, konec fajlu nebo hloubky hledani
state = States::Error;
return -1;
}
}
// [[fallthrough]]; // here is no break intentionally
case States::Base64: {
int i = 0; // spravne by to melo byt unsigned, ale chci eliminovat
// warning i == n, pricemz n je definitoricky int
for (;;) {
// tady nemusim cist po radkach, akorat pak bych musel naprasit
// automat na hledani ; thumbnail end, coz se mi nechce nicmene ten
// vysledek musim prehodit do nejakyho zpracovanyho pole
if (bytesQ.isEmpty()) {
SLine l;
// nutno nacist dalsi line
if (!ReadLine(f, l)) {
state = States::Error; // rozbite, predcasny konec fajlu
return -1;
}
// kontrola, ze se precetla cela radka a nic se z toho
// nezahodilo v rezimu cteni base64 je to dulezite, nemuzu nic
// zahodit, rozbil bych si data
if (l.expectedLineSize > l.size) {
state = States::Error; // rozbite, moc dlouha radka
return -1;
}
if (l.IsEndThumbnail()) {
state = States::End; // platny konec thumbnailu
return i; // uz je EOF, nemam dalsi data, ale automat konci
// spravnym koncem
// vracim, kolik jsem dosud nactetl
} else if (LineIsBase64(l, bytesQ)) {
// line nactena v poradku a zdekodovana, stav base64
// zustava, ocekava se dalsi takova radka
} else {
state = States::Error;
return -1;
}
}
// tady zamerne NENI else
if (!bytesQ.isEmpty()) {
*(pc + i) = bytesQ.dequeue();
++i;
if (i == n)
break;
}
}
return i;
}
default: // ve vsech ostatnich stavech vratit -1, nemam data, ani kdybych se
// rozkrajel
return -1;
}
}