diff options
-rw-r--r-- | src/mot-encoder.cpp | 219 |
1 files changed, 126 insertions, 93 deletions
diff --git a/src/mot-encoder.cpp b/src/mot-encoder.cpp index afcbd86..ce61e9f 100644 --- a/src/mot-encoder.cpp +++ b/src/mot-encoder.cpp @@ -229,18 +229,63 @@ void createMscDG(MSCDG* msc, unsigned short int dgtype, int *cindex, unsigned sh unsigned short int lastseg, unsigned short int tid, unsigned char* data, unsigned short int datalen); -void packMscDG(unsigned char* mscblob, MSCDG* msc, unsigned short int *bsize); +struct DATA_GROUP; +DATA_GROUP* packMscDG(MSCDG* msc); void writeMotPAD(int output_fd, - unsigned char* mscdg, - unsigned short int mscdgsize, + DATA_GROUP* mscdg, unsigned short int padlen); -void create_dls_pads(const std::string& text, const int padlen, const uint8_t charset); +void create_dls_pads(const std::string& text, int padlen, uint8_t charset); void writeDLS(int output_fd, const std::string& dls_file, int padlen, uint8_t charset, bool raw_dls); +// PAD related +#define CRC_LEN 2 +typedef std::vector<uint8_t> uint8_vector_t; + +struct DATA_GROUP { + uint8_vector_t data; + int apptype_start; + int apptype_cont; + size_t written; + + DATA_GROUP(size_t len, int apptype_start, int apptype_cont) { + this->data.resize(len); + this->apptype_start = apptype_start; + this->apptype_cont = apptype_cont; + written = 0; + } + + void AppendCRC() { + uint16_t crc = 0xFFFF; + for (size_t i = 0; i < data.size(); i++) + crc = update_crc_ccitt(crc, data[i]); + crc = ~crc; +#if DEBUG + fprintf(stderr, "crc=%04x ~crc=%04x\n", crc, ~crc); +#endif + + data.push_back((crc & 0xFF00) >> 8); + data.push_back((crc & 0x00FF)); + } + + size_t Available() { + return data.size() - written; + } + + size_t WriteReversed(uint8_t *write_data, size_t len) { + size_t written_now = std::min(len, Available()); + + for (size_t off = 0; off < written_now; off++) + write_data[-off] = data[written + off]; + + written += written_now; + return written_now; + } +}; int get_xpadlengthmask(int padlen); size_t get_xpadlength(int mask); + #define SHORT_PAD 6 #define ALLOWED_PADLEN "6 (short X-PAD; only DLS), 23, 26, 34, 42, 58" @@ -254,12 +299,10 @@ static int cindex_body = 0; #define FPAD_LEN 2 #define DLS_SEG_LEN_PREFIX 2 #define DLS_SEG_LEN_CHAR_MAX 16 -#define DLS_SEG_LEN_CRC 2 -#define DLS_SEG_LEN_MAX (DLS_SEG_LEN_PREFIX + DLS_SEG_LEN_CHAR_MAX + DLS_SEG_LEN_CRC) CharsetConverter charset_converter; -typedef std::vector<uint8_t> pad_t; +typedef uint8_vector_t pad_t; static std::deque<pad_t> dls_pads; static bool dls_toggle = false; std::string dlstext_prev = ""; @@ -562,6 +605,22 @@ int main(int argc, char *argv[]) return 1; } + +DATA_GROUP* createDataGroupLengthIndicator(size_t len) { + DATA_GROUP* dg = new DATA_GROUP(2, 1, -1); // continuation never used + uint8_vector_t &data = dg->data; + + // Data Group length + data[0] = (len & 0x3F00) >> 8; + data[1] = (len & 0x00FF); + + // CRC + dg->AppendCRC(); + + return dg; +} + + // Resize the image or add a black border around it // so that it is 320x240 pixels. // Automatically reduce the quality to make sure the @@ -638,8 +697,7 @@ int encodeFile(int output_fd, std::string& fname, int fidx, int padlen, bool raw unsigned char *blob = NULL; unsigned char *curseg = NULL; MSCDG msc; - unsigned char mscblob[9 + MAXSEGLEN + 2]; // headers + segment + CRC - unsigned short int mscblobsize; + DATA_GROUP* mscdg; size_t orig_quality; char* orig_format = NULL; @@ -807,8 +865,9 @@ int encodeFile(int output_fd, std::string& fname, int fidx, int padlen, bool raw // Create the MSC Data Group C-Structure createMscDG(&msc, 3, &cindex_header, 0, 1, fidx, mothdr, mothdrlen); // Generate the MSC DG frame (Figure 9 en 300 401) - packMscDG(mscblob, &msc, &mscblobsize); - writeMotPAD(output_fd, mscblob, mscblobsize, padlen); + mscdg = packMscDG(&msc); + writeMotPAD(output_fd, mscdg, padlen); + delete mscdg; for (i = 0; i < nseg; i++) { curseg = blob + i * MAXSEGLEN; @@ -822,8 +881,9 @@ int encodeFile(int output_fd, std::string& fname, int fidx, int padlen, bool raw } createMscDG(&msc, 4, &cindex_body, i, last, fidx, curseg, curseglen); - packMscDG(mscblob, &msc, &mscblobsize); - writeMotPAD(output_fd, mscblob, mscblobsize, padlen); + mscdg = packMscDG(&msc); + writeMotPAD(output_fd, mscdg, padlen); + delete mscdg; } ret = 1; @@ -909,11 +969,12 @@ void createMscDG(MSCDG* msc, unsigned short int dgtype, } -void packMscDG(unsigned char* b, MSCDG* msc, unsigned short int* bsize) +DATA_GROUP* packMscDG(MSCDG* msc) { - int i; - unsigned short int crc=0xFFFF; + DATA_GROUP* dg = new DATA_GROUP(9 + msc->seglen, 12, 13); + uint8_vector_t &b = dg->data; + // headers b[0] = (msc->extflag<<7) | (msc->crcflag<<6) | (msc->segflag<<5) | (msc->accflag<<4) | msc->dgtype; @@ -927,22 +988,13 @@ void packMscDG(unsigned char* b, MSCDG* msc, unsigned short int* bsize) b[7] = (msc->rcount << 5) | ((msc->seglen & 0x1F00)>>8); b[8] = msc->seglen & 0x00FF; - for (i = 0; i<9; i++) { - crc = update_crc_ccitt(crc, b[i]); - } - - for(i = 0; i < msc->seglen; i++) { - b[i+9] = (msc->segdata)[i]; - crc = update_crc_ccitt(crc, b[i+9]); - } + // data field + memcpy(&b[9], msc->segdata, msc->seglen); - crc = ~crc; - b[9+msc->seglen] = (crc & 0xFF00) >> 8; // HI CRC - b[9+msc->seglen+1] = crc & 0x00FF; // LO CRC - - *bsize = 9 + msc->seglen + 2; + // CRC + dg->AppendCRC(); - //write(1,b,9+msc->seglen+1+1); + return dg; } @@ -1017,19 +1069,16 @@ int dls_count(const std::string& text) { } -size_t dls_get(const std::string& text, const uint8_t charset, const unsigned int seg_index, uint8_t *seg_data) { - int seg_count = dls_count(text); - if (seg_index >= seg_count) - return 0; - +DATA_GROUP* dls_get(const std::string& text, uint8_t charset, unsigned int seg_index) { bool first_seg = seg_index == 0; - bool last_seg = seg_index == seg_count - 1; + bool last_seg = seg_index == dls_count(text) - 1; int seg_text_offset = seg_index * DLS_SEG_LEN_CHAR_MAX; const char *seg_text_start = text.c_str() + seg_text_offset; size_t seg_text_len = MIN(text.size() - seg_text_offset, DLS_SEG_LEN_CHAR_MAX); - size_t seg_len = DLS_SEG_LEN_PREFIX + seg_text_len + DLS_SEG_LEN_CRC; + DATA_GROUP* dg = new DATA_GROUP(DLS_SEG_LEN_PREFIX + seg_text_len, 2, 3); + uint8_vector_t &seg_data = dg->data; // prefix: toggle? + first seg? + last seg? + (seg len - 1) seg_data[0] = @@ -1042,31 +1091,22 @@ size_t dls_get(const std::string& text, const uint8_t charset, const unsigned in seg_data[1] = (first_seg ? charset : seg_index) << 4; // character field - memcpy(seg_data + DLS_SEG_LEN_PREFIX, seg_text_start, seg_text_len); + memcpy(&seg_data[DLS_SEG_LEN_PREFIX], seg_text_start, seg_text_len); // CRC - uint16_t crc = 0xFFFF; - for (int i = 0; i < seg_len - DLS_SEG_LEN_CRC; i++) - crc = update_crc_ccitt(crc, seg_data[i]); - crc = ~crc; -#if DEBUG - fprintf(stderr, "crc=%04x ~crc=%04x\n", ~crc, crc); -#endif - seg_data[seg_len - 2] = (crc & 0xFF00) >> 8; // HI CRC - seg_data[seg_len - 1] = crc & 0x00FF; // LO CRC + dg->AppendCRC(); #if DEBUG fprintf(stderr, "DL segment:"); - for (int i = 0; i < seg_len; i++) + for (int i = 0; i < seg_data.size(); i++) fprintf(stderr, " %02x", seg_data[i]); fprintf(stderr, "\n"); #endif - return seg_len; + return dg; } -void create_dls_pads(const std::string& text, const int padlen, const uint8_t charset) { - uint8_t seg_data[DLS_SEG_LEN_MAX]; +void create_dls_pads(const std::string& text, int padlen, uint8_t charset) { int xpadlengthmask = get_xpadlengthmask(padlen); dls_pads.clear(); @@ -1078,18 +1118,18 @@ void create_dls_pads(const std::string& text, const int padlen, const uint8_t ch #if DEBUG fprintf(stderr, "Segment number %d\n", seg_index + 1); #endif - int seg_len = dls_get(text, charset, seg_index, seg_data); + DATA_GROUP* seg = dls_get(text, charset, seg_index); + bool ci_needed = true; // CI needed only at first data group int dg_len; int used_xpad_len; // distribute the segment over one or more PADs - for (int seg_off = 0; seg_off < seg_len;) { + while (seg->Available()) { dls_pads.push_back(pad_t(padlen + 1)); pad_t &pad = dls_pads.back(); int pad_off = padlen - 1; bool var_size_pad = padlen != SHORT_PAD; - bool ci_needed = seg_off == 0; // CI needed only at first data group if (ci_needed) { dg_len = get_xpadlength(xpadlengthmask); @@ -1099,7 +1139,7 @@ void create_dls_pads(const std::string& text, const int padlen, const uint8_t ch } else { dg_len = used_xpad_len; } - int dg_used = MIN(dg_len, seg_len - seg_off); + int dg_used = MIN(dg_len, seg->Available()); // F-PAD Byte L (CI if needed) @@ -1110,15 +1150,15 @@ void create_dls_pads(const std::string& text, const int padlen, const uint8_t ch // CI (app type 2 = DLS, start of X-PAD data group) if (ci_needed) - pad[pad_off--] = ((var_size_pad ? xpadlengthmask : 0) << 5) | 0x02; + pad[pad_off--] = ((var_size_pad ? xpadlengthmask : 0) << 5) | seg->apptype_start; // CI end marker if (ci_needed && var_size_pad) pad[pad_off--] = 0x00; // segment (part) - for (int i = 0; i < dg_used; i++) - pad[pad_off--] = seg_data[seg_off + i]; + seg->WriteReversed(&pad[pad_off], dg_used); + pad_off -= dg_used; // NULL PADDING std::fill_n(pad.begin(), pad_off + 1, 0x00); @@ -1132,8 +1172,12 @@ void create_dls_pads(const std::string& text, const int padlen, const uint8_t ch fprintf(stderr, " %02x", pad[i]); fprintf(stderr, "\n"); #endif - seg_off += dg_used; + + if (ci_needed) + ci_needed = false; } + + delete seg; } #if DEBUG fprintf(stderr, "PAD length: %d\n", padlen); @@ -1143,44 +1187,38 @@ void create_dls_pads(const std::string& text, const int padlen, const uint8_t ch #endif } + void writeMotPAD(int output_fd, - unsigned char* mscdg, - unsigned short int mscdgsize, + DATA_GROUP* mscdg, unsigned short int padlen) { unsigned char pad[padlen + 1]; - int xpadlengthmask, i, j, k; - unsigned short int crc; + int xpadlengthmask, k; + bool firstseg = true; xpadlengthmask = get_xpadlengthmask(padlen); // Write MSC Data Groups int curseglen, used_xpad_len; - for (i = 0; i < mscdgsize; i += curseglen) { - uint8_t* curseg; - uint8_t firstseg; - - curseg = &mscdg[i]; + while (mscdg->Available()) { #if DEBUG fprintf(stderr,"Segment offset %d\n",i); #endif - if (i == 0) { // First segment - firstseg = 1; + if (firstseg) { // First segment curseglen = get_xpadlength(xpadlengthmask); // size of first X-PAD = MSC-DG + DGLI-DG + End of CI list + 2x CI = size of subsequent non-CI X-PADs used_xpad_len = curseglen + 4 + 1 + 2; } else { - firstseg = 0; curseglen = used_xpad_len; } - curseglen = MIN(curseglen, mscdgsize - i); + curseglen = MIN(curseglen, mscdg->Available()); - if (firstseg == 1) { + if (firstseg) { // FF-PAD Byte L (CI=1) pad[padlen-1] = 0x02; @@ -1188,23 +1226,18 @@ void writeMotPAD(int output_fd, pad[padlen-2] = 0x20; // Write Data Group Length Indicator - crc = 0xffff; + DATA_GROUP* dgli = createDataGroupLengthIndicator(mscdg->data.size()); + // CI for data group length indicator: data length=4, Application Type=1 - pad[padlen-3]=0x01; - // CI for data group length indicator: Application Type=12 (Start of MOT) - pad[padlen-4]=(xpadlengthmask<<5) | 12; + pad[padlen-3]=(0<<5) | dgli->apptype_start; + // CI for MOT, start of X-PAD data group: Application Type=12 + pad[padlen-4]=(xpadlengthmask<<5) | mscdg->apptype_start; // End of CI list pad[padlen-5]=0x00; - // RFA+HI Data group length - pad[padlen-6]=(mscdgsize & 0x3F00)>>8; - pad[padlen-7]=(mscdgsize & 0x00FF); - crc = update_crc_ccitt(crc, pad[padlen-6]); - crc = update_crc_ccitt(crc, pad[padlen-7]); - crc = ~crc; - // HI CRC - pad[padlen-8]=(crc & 0xFF00) >> 8; - // LO CRC - pad[padlen-9]=(crc & 0x00FF); + + dgli->WriteReversed(&pad[padlen-6], 4); + delete dgli; + k=10; } else { @@ -1216,12 +1249,9 @@ void writeMotPAD(int output_fd, k=3; } - for (j = 0; j < curseglen; j++) { - pad[padlen-k-j] = curseg[j]; - } - for (j = padlen-k-curseglen; j >= 0; j--) { - pad[j] = 0x00; - } + mscdg->WriteReversed(&pad[padlen-k], curseglen); + + memset(pad, 0x00, padlen-k-curseglen + 1); // set used pad len pad[padlen] = FPAD_LEN + used_xpad_len; @@ -1233,6 +1263,9 @@ void writeMotPAD(int output_fd, fprintf(stderr,"%02x ",pad[j]); fprintf(stderr,"\n"); #endif + + if (firstseg) + firstseg = false; } } |