#include "mkhiblib.h" /** * Change the current study position to the next line. The final position will be * the position of the 'return' character ('13') or of the final character ('\0'). * * @param hfile the file to study * @param hstudy the study datas */ void hskipLine(h_File * hfile, h_Study * hstudy) { while (hfile->text[hstudy->pos_txt] != 13 && hfile->text[hstudy->pos_txt] != '\0') { hstudy->pos_txt++; } } /** * Add a log entry * * @param num_error the number of the error * @param pos_txt the position of the error in the text * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL haddLog(short num_error, unsigned short pos_txt, h_File * hfile, h_Study * hstudy) { short num_log; hl_unlockhFile(hfile); num_log = hl_addHANDLE(&(hfile->h_logs), &(hfile->nb_logs), &(hstudy->size_logs), sizeof(h_Log)); hl_lockhFile(hfile); if (num_log == NOK) { return FALSE; } hfile->hlogs[num_log].num_error = num_error; hfile->hlogs[num_log].pos_txt = pos_txt; return TRUE; } /** * Copy a token in a buffer. The token is read from the text. The token must be finished * by the character '=', an end of line or an end of text * The token can't take more than 19 characters, so the buffer have to be at least 20 * bytes long. * * @param buffer the buffer which will contain the token * @param text the text to parse */ void hcopyToken(unsigned char * buffer, const unsigned char * text) { short length = 0; while (*text != '=' && *text != 13 && *text != '\0' && length < 19) { *(buffer++) = *(text++); length++; } *buffer = '\0'; } /** * Parse the header * * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseHeader(h_File * hfile, h_Study * hstudy) { unsigned char token[20]; while (hfile->text[hstudy->pos_txt + 1] == 169) { //'(C)' = 169 = the comments caracter hstudy->pos_txt++; hcopyToken(token, hfile->text + (++hstudy->pos_txt)); if (strcmp(token, "TITLE") == 0) { //definition of the title of the text hstudy->pos_txt += 6; hfile->hh.pos_title = hstudy->pos_txt; } else if (strcmp(token, "AUTHOR") == 0) { //definition of the auther of the text hstudy->pos_txt += 7; hfile->hh.pos_author = hstudy->pos_txt; } else if (strcmp(token, "DATE") == 0) { //definition of the date of the text hstudy->pos_txt += 5; hfile->hh.pos_date = hstudy->pos_txt; } else if (strcmp(token, "COMMENT") == 0) { //definition of the comment of the text hstudy->pos_txt += 8; hfile->hh.pos_comment = hstudy->pos_txt; } else if (token[0] == '#' && token[1] >= '0' && token[1] <= '9' && token[2] == '\0') { //definition of the font used hstudy->pos_txt += 3; hfile->hh.pos_name_font[token[1] - '0'] = hstudy->pos_txt; } else { if (!haddLog(HLOG_BAD_HEADER, hstudy->pos_txt, hfile, hstudy)) { return FALSE; } } hskipLine(hfile, hstudy); if (hfile->text[hstudy->pos_txt] == 13) { hstudy->pos_txt++; } } return TRUE; } /** * Parse a bookmark * The current position have to be just after the 'page-break' character * * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseBookmark(h_File * hfile, h_Study * hstudy) { short num_bkmk; hl_unlockhFile(hfile); num_bkmk = hl_addHANDLE(&(hfile->h_bkmks), &(hfile->nb_bkmks) ,&(hstudy->size_bkmks), sizeof(h_Bookmark)); if (num_bkmk==NOK) { return FALSE; } num_bkmk = hl_addHANDLE(&(hfile->h_bkmks_level), &(hstudy->nb_bkmks_level), &(hstudy->size_bkmks_level), sizeof(h_MenuLevel)); if (num_bkmk==NOK) { return FALSE; } hl_lockhFile(hfile); hfile->hbkmks[num_bkmk].pos_txt = hstudy->pos_txt - 1; hfile->hbkmks_level[num_bkmk] = (h_MenuLevel) { .level=0, .hide=0, .draw=1 }; //search if a bookmark title is defined if (hfile->text[hstudy->pos_txt] == '&' && hfile->text[hstudy->pos_txt + 1] == 'T') { hstudy->pos_txt += 2; if (hfile->text[hstudy->pos_txt] >= '0' && hfile->text[hstudy->pos_txt] <= '9') { //a definition of the level of the title hfile->hbkmks_level[num_bkmk].level = hfile->text[hstudy->pos_txt++] - '0'; } hfile->hbkmks[num_bkmk].pos_txt = hstudy->pos_txt; if (hfile->text[hstudy->pos_txt] != '&' || hfile->text[hstudy->pos_txt + 1] != 'T') { //skip the title while (hfile->text[hstudy->pos_txt] != 13 && hfile->text[hstudy->pos_txt] != '\0' && !(hfile->text[hstudy->pos_txt] == '&' && hfile->text[hstudy->pos_txt + 1] == 'T')) { if (hfile->text[hstudy->pos_txt] == '&' && hfile->text[hstudy->pos_txt + 1] == '&') { hstudy->pos_txt++; } hstudy->pos_txt++; } } if (hfile->text[hstudy->pos_txt] == '&' && hfile->text[hstudy->pos_txt + 1] == 'T') { hstudy->pos_txt += 2; } } return TRUE; } /** * Parse a format of line * The current position have to be just after the 'page-break' character * * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseFrtLine(h_FrtLine * current_frtline, h_File * hfile, h_Study * hstudy) { unsigned char caract1 = 0; unsigned char caract2 = 0; unsigned char caract3 = 0; while (hfile->text[hstudy->pos_txt] == '&') { hstudy->pos_txt++; switch (hfile->text[hstudy->pos_txt++]) { case 'L': //left alignement current_frtline->align = HALIGN_LEFT; break; case 'C': //center current_frtline->align = HALIGN_CENTER; break; case 'R': //right alignement current_frtline->align = HALIGN_RIGHT; break; case 'J': //justified current_frtline->align = HALIGN_JUSTIFIED; break; case '\\': // margin of 0 current_frtline->margin = 0; break; case ',': // margin of 10 current_frtline->margin = 10; break; case ';': // margin of 20 current_frtline->margin = 20; break; case '.': // margin of 30 current_frtline->margin = 30; break; case 'M': //personalised margin caract1 = hfile->text[hstudy->pos_txt++]; caract2 = hfile->text[hstudy->pos_txt++]; caract3 = hfile->text[hstudy->pos_txt++]; if (caract1 >= '0' && caract1 <= '9' && caract2 >= '0' && caract2 <= '9' && caract3 >= '0' && caract3 <= '9') { short margin = (caract3 - '0') + 10 * (caract2 - '0') + 100 * (caract1 - '0'); //new margin if (margin > 255) { if (!haddLog(HLOG_BIG_MARGIN, hstudy->pos_txt, hfile, hstudy)) { return FALSE; } margin = 255; } current_frtline->margin = margin; break; } hstudy->pos_txt -= 5; //bad syntax : return the caracter & if (!haddLog(HLOG_MARGIN, hstudy->pos_txt, hfile, hstudy)) { return FALSE; } return TRUE; default: hstudy->pos_txt -= 2; //doesn't log it : it can be an object of line return TRUE; } } return TRUE; } /** * Create a new hObject * * @param hobj the h_Object to add * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hnewObject(h_Object hobj, h_File * hfile, h_Study * hstudy) { short no_obj; hl_unlockhFile(hfile); no_obj = hl_addHANDLE(&(hfile->h_objs), &(hfile->nb_objs), &(hstudy->size_objs), sizeof(h_Object)); if (no_obj == NOK) { return FALSE; } hl_lockhFile(hfile); hfile->hobjs[no_obj] = hobj; return TRUE; } /** * Parse an object of a Ti-OS line (begins with '&') * * @param is_obj says if an object was parsed or not (updated by the function) * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseObjectLine(BOOL * is_obj, h_File * hfile, h_Study * hstudy) { short caract = 0; *is_obj = FALSE; if (hfile->text[hstudy->pos_txt] != '&') return TRUE; hstudy->pos_txt++; caract = hfile->text[hstudy->pos_txt]; switch (caract) { case '&': //draw a & return TRUE; case 'P': //a picture caract = HOBJECT_PIC; break; case 'E': //un pretty print caract = HOBJECT_PPRINT; break; case '-': //simple separating line caract = HOBJECT_SEPARAT1; break; case '=': //double separating line caract = HOBJECT_SEPARAT2; break; default: hstudy->pos_txt--; if (!haddLog(HLOG_FORMAT_LINE, hstudy->pos_txt, hfile, hstudy)) { return FALSE; } return TRUE; } hstudy->pos_txt++; if (!hnewObject((h_Object){.pos_txt=hstudy->pos_txt, .datas={.pic={.wrong=TRUE}}, .type=caract}, hfile, hstudy)) { return FALSE; } hskipLine(hfile,hstudy); //copy the name of the picture in the htxt text if (hfile->text[hstudy->pos_txt] == 13) { hstudy->pos_txt++; } *is_obj = TRUE; return TRUE; } /** * Parse a text format * * * * @param start_pos_txt the position in the text where the object begins. Normally, it's just before * a changing format. So this value is set to the current position just before the calling of this * function. But for format, the start of the object is after the target definition. This parameter * will only be updated in this case. * @param chg_frt says if there is a changing of format or not (updated by the function) * @param current_frt the current format (updated by the function) * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseFormat(unsigned short * start_pos_txt, BOOL * chg_frt, h_Format * current_frt, h_File * hfile, h_Study * hstudy) { unsigned char caract; *chg_frt = FALSE; while (1) { if (hfile->text[hstudy->pos_txt]!='#') { return TRUE; } caract = hfile->text[++hstudy->pos_txt]; hstudy->pos_txt++; switch (caract) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': caract -= '0'; if (hfile->hh.pos_name_font[caract] == NOK) { //this font is not defined if (!haddLog(HLOG_FONT_NOT_DEFINED, hstudy->pos_txt, hfile, hstudy)) return FALSE; hstudy->pos_txt -= 2; return TRUE; } current_frt->num_font = caract; //change the font *chg_frt = TRUE; continue; case 'W': //wordwarp option current_frt->wordwarp =~ current_frt->wordwarp; *chg_frt = TRUE; continue; case 'U': //underline current_frt->underline = !(current_frt->underline || current_frt->dotted); current_frt->dotted = 0; *chg_frt = TRUE; continue; case 'N': //dotted underline current_frt->dotted = !(current_frt->underline || current_frt->dotted); current_frt->underline = 0; *chg_frt = TRUE; continue; case 'J': //conjugate current_frt->conjug = !(current_frt->conjug || current_frt->vector); current_frt->vector = 0; *chg_frt = TRUE; continue; case 'V': //a vector current_frt->vector = !(current_frt->conjug || current_frt->vector); current_frt->conjug = 0; *chg_frt = TRUE; continue; case 'S': //strikethrought current_frt->strike = ~current_frt->strike; *chg_frt = TRUE; continue; case 'i': //italic current_frt->italic = ~current_frt->italic; *chg_frt = TRUE; continue; case 'B': //bold current_frt->bold = ~current_frt->bold; *chg_frt = TRUE; continue; case 'I': //inversed color current_frt->inversed = ~current_frt->inversed; *chg_frt = TRUE; continue; case 'E': //exponent current_frt->exponent = ~current_frt->exponent; current_frt->suffix = 0; *chg_frt = TRUE; continue; case 'D': //suffix current_frt->suffix = ~current_frt->suffix; current_frt->exponent = 0; *chg_frt = TRUE; continue; case 'L': //hypertext link current_frt->link = ~current_frt->link; if (current_frt->link != 0) { hfile->nb_targetlinks++; if (!hnewObject((h_Object){.pos_txt = hstudy->pos_txt - 2, .type = HOBJECT_LINK}, hfile, hstudy)) { return FALSE; } //skip the path of link while ( hfile->text[hstudy->pos_txt] != '#' && hfile->text[hstudy->pos_txt] != 13 && hfile->text[hstudy->pos_txt] != '\0' ) { hstudy->pos_txt++; } if (hfile->text[hstudy->pos_txt] == 13 || hfile->text[hstudy->pos_txt] == '\0') { if (!haddLog(HLOG_BAD_LINK, hstudy->pos_txt, hfile, hstudy)) { return FALSE; } return TRUE; } hstudy->pos_txt += 2; *start_pos_txt = hstudy->pos_txt; } *chg_frt = TRUE; continue; default: //no caracter of format hstudy->pos_txt -= 2; //don't log it as a error : it can be a special character return TRUE; }//end of switch } return TRUE; } /** * Parse a character * This function assumes that there is no format at the current position * * @param hfile the file to study * @param hstudy the study datas * * @return the found character, NOK (-1) is case of memory error */ short hparseCaract(h_File * hfile, h_Study * hstudy) { unsigned char caract1; unsigned char caract2; unsigned char caract3; short j; caract1 = hfile->text[hstudy->pos_txt++]; if (caract1 == '#') { //can be special caracter. caract2 = hfile->text[hstudy->pos_txt++]; switch (caract2) { case '#': //only draw # return '#'; case 'C': //caracter definition caract1 = hfile->text[hstudy->pos_txt++]; caract2 = hfile->text[hstudy->pos_txt++]; caract3 = hfile->text[hstudy->pos_txt++]; if ( caract1 >= '0' && caract1 <= '9' && caract2 >= '0' && caract2 <= '9' && caract3 >= '0' && caract3 <= '9' ) { //there must be 3 caracters j = (caract3 - '0') + 10 * (caract2 - '0') + 100 * (caract1 - '0'); if (j < 256) { //there are only 256 caracters if (j != 10 && j != 0) { return j; } hstudy->pos_txt -= 4; //the caracter 10 and the caracter 0 are forbidden if (j == 10) { if (!haddLog(HLOG_SPECIAL_CARACT10, hstudy->pos_txt, hfile, hstudy)) { return NOK; } } else { if (!haddLog(HLOG_SPECIAL_CARACT0, hstudy->pos_txt, hfile, hstudy)) { return NOK; } } return '#'; } else if (j < NB_SPECIAL_CARACTERS+256) { return j; } } hstudy->pos_txt -= 4; //wrong syntax if (!haddLog(HLOG_SPECIAL_CARACT, hstudy->pos_txt, hfile, hstudy)) { return NOK; } return '#'; default: //no caracter of format hstudy->pos_txt--; if (!haddLog(HLOG_FORMAT_CARACT, hstudy->pos_txt, hfile, hstudy)) { return NOK; } }//end of switch } return caract1; } /** * Parse a Ti-OS Line * * @param current_frt the current format * @param hfile the file to study * @param hstudy the study datas * * @return FALSE in case of memory error, else TRUE */ BOOL hparseLine(h_Format * current_frt, h_File * hfile, h_Study * hstudy) { short caract; BOOL chg_frt = FALSE; BOOL begin_line = TRUE; unsigned short start_pos_txt; do { start_pos_txt = hstudy->pos_txt; if (!hparseFormat(&start_pos_txt, &chg_frt, current_frt, hfile, hstudy)) { return FALSE; } //read the caracter or object caract = hparseCaract(hfile, hstudy); if (caract == NOK) { return FALSE; } if (caract == 13 || caract == '\0') { if (begin_line) { //it's the end of a TIOS line //create an empty text object if it is empty line if (!hnewObject((h_Object){.pos_txt = hstudy->pos_txt - 1, .datas.frt = *current_frt, .type= HOBJECT_TEXT}, hfile, hstudy)) { return FALSE; } } } else if (caract > 0 && caract < 256 + NB_SPECIAL_CARACTERS) { //it's a normal caracter if (chg_frt || begin_line) { //create the object if (!hnewObject((h_Object){.pos_txt = start_pos_txt, .datas.frt = *current_frt, .type=HOBJECT_TEXT}, hfile, hstudy)) { return FALSE; } begin_line = FALSE; } } } while (caract != '\0' && caract != 13); if (caract == '\0') { hstudy->pos_txt--; } return TRUE; } /** * Parse a text a make it a hfile * * @param hfile the h_File struct to fill * @param text the text to parse * @param size_text the size of the text * * @return FALSE if there is a memory error */ BOOL hl_parse(h_File * hfile, const unsigned char * text, unsigned short size_text) { h_Study hstudy = { .pos_txt = 0, .size_objs = (size_text >> 5) + 20, .size_logs = 1, .size_links = 1, .size_bkmks = 1, .size_bkmks_level = 1, .size_text_bkmk = 20, .nb_bkmks_level = 0 }; h_Format current_frt = { .num_font = 2, .underline = 0, .dotted = 0, .vector = 0, .conjug = 0, .strike = 0, .exponent = 0, .suffix = 0, .inversed = 0, .wordwarp = 0, .link = 0, .italic = 0, .bold = 0 }; h_FrtLine current_frtline = { .margin = 0, .align = HALIGN_LEFT }; *hfile = (h_File) { .isPic = FALSE, .text = text, .size_text = size_text, .hh = (h_Header) { .pos_title = NOK, .pos_author = NOK, .pos_date = NOK, .pos_comment = NOK, .pos_name_font = { NOK, 0, 0, 0, NOK, NOK, NOK, NOK, NOK, NOK } }, .nb_targetlinks = 0, .nb_tioslines = 0, .h_buffer = H_NULL, .h_scrlines = H_NULL, .h_links = H_NULL, .buffer.pos.y = 0, .buffer.pos.x = 0 }; unsigned short start_pos_txt; //creation of the tables hfile->nb_logs = 0; hfile->h_logs = HeapAlloc(hstudy.size_logs * sizeof(h_Log)); if (hfile->h_logs == H_NULL) { goto mem2; } hfile->nb_bkmks = 0; hfile->h_bkmks = HeapAlloc(hstudy.size_bkmks * sizeof(h_Bookmark)); if (hfile->h_bkmks == H_NULL) { goto mem3; } hstudy.nb_bkmks_level = 0; hfile->h_bkmks_level = HeapAlloc(hstudy.size_bkmks_level * sizeof(h_MenuLevel)); if (hfile->h_bkmks_level == H_NULL) { goto mem4; } hfile->nb_objs = 0; hfile->h_objs = HeapAlloc(hstudy.size_objs * sizeof(h_Object)); if (hfile->h_objs == H_NULL) { goto mem5; } //"create" the first hObject hl_lockhFile(hfile); //read the header if (!hparseHeader(hfile, &hstudy)) { HeapFree(hfile->h_objs); mem5: HeapFree(hfile->h_bkmks_level); mem4: HeapFree(hfile->h_bkmks); mem3: HeapFree(hfile->h_logs); mem2: hfile->text = NULL; return FALSE; } BOOL is_obj = FALSE; //study the text do { start_pos_txt = hstudy.pos_txt; if (text[hstudy.pos_txt++] == 12) { // a bookmark if (!hparseBookmark(hfile, &hstudy)) { mem: hl_freehFile(hfile); return FALSE; } } if (!hparseFrtLine(¤t_frtline, hfile, &hstudy)) { goto mem; } //set a format of line if (!hnewObject((h_Object){.pos_txt = start_pos_txt, .datas.frtline = current_frtline, .type=HOBJECT_TIOS_LINE}, hfile, &hstudy)) { goto mem; } //study if there is an object of line if (!hparseObjectLine(&is_obj ,hfile, &hstudy)) { goto mem; } if (!is_obj) { //if there is no line object //study the line if (!hparseLine(¤t_frt, hfile, &hstudy)) { goto mem; } } hfile->nb_tioslines++; } while (text[hstudy.pos_txt] != '\0'); //until the end of the text if (!hnewObject((h_Object){.pos_txt = hstudy.pos_txt, .type=HOBJECT_END_TEXT}, hfile, &hstudy)) { goto mem; } return TRUE; }