From e95cbdd7bb8affcae797bd622668c9ad8bb573ea Mon Sep 17 00:00:00 2001 From: cfif Date: Mon, 2 Jun 2025 13:26:41 +0300 Subject: [PATCH] Init --- Inc/SmsCharMap.h | 147 ++++ Inc/SmsEncoderDecoder.h | 119 +++ Inc/SmsEncoderDecoderPrivate.h | 85 ++ Inc/SmsUtfUtils.h | 87 ++ Src/SmsEncoderDecoder.c | 1373 ++++++++++++++++++++++++++++++++ Src/SmsUtfUtils.c | 615 ++++++++++++++ modular.json | 17 + 7 files changed, 2443 insertions(+) create mode 100644 Inc/SmsCharMap.h create mode 100644 Inc/SmsEncoderDecoder.h create mode 100644 Inc/SmsEncoderDecoderPrivate.h create mode 100644 Inc/SmsUtfUtils.h create mode 100644 Src/SmsEncoderDecoder.c create mode 100644 Src/SmsUtfUtils.c create mode 100644 modular.json diff --git a/Inc/SmsCharMap.h b/Inc/SmsCharMap.h new file mode 100644 index 0000000..c3eec57 --- /dev/null +++ b/Inc/SmsCharMap.h @@ -0,0 +1,147 @@ +/* + * alphabet.h + * + * Created on: Dec 8, 2020 + * Author: FICOM-IT LTD + */ + +#ifndef SMS_INC_CHRMAP_H_ +#define SMS_INC_CHRMAP_H_ + +#include "stdint.h" + +typedef struct { + unsigned short key; + unsigned short value; +} tSmsCharMapNode; + +#define SMS_DC_EC_MAP_SIZE(map) (sizeof(map) / sizeof(tSmsCharMapNode)) + +// Unicode +tSmsCharMapNode UCS2ToBIT7[] = { + {0x000C, 0x1B0A}, + {0x0024, 0x0002}, + {0x0040, 0x0000}, + {0x005B, 0x1B3C}, + {0x005C, 0x1B2F}, + {0x005D, 0x1B3E}, + {0x005E, 0x1B14}, + {0x005F, 0x0011}, + {0x007B, 0x1B28}, + {0x007C, 0x1B40}, + {0x007D, 0x1B29}, + {0x007E, 0x1B3D}, + {0x00A0, 0x001B}, + {0x00A1, 0x0040}, + {0x00A3, 0x0001}, + {0x00A4, 0x0024}, + {0x00A5, 0x0003}, + {0x00A7, 0x005F}, + {0x00BF, 0x0060}, + {0x00C4, 0x005B}, + {0x00C5, 0x000E}, + {0x00C6, 0x001C}, + {0x00C9, 0x001F}, + {0x00D1, 0x005D}, + {0x00D6, 0x005C}, + {0x00D8, 0x000B}, + {0x00DC, 0x005E}, + {0x00DF, 0x001E}, + {0x00E0, 0x007F}, + {0x00E4, 0x007B}, + {0x00E5, 0x000F}, + {0x00E6, 0x001D}, + {0x00E7, 0x0009}, + {0x00E8, 0x0004}, + {0x00E9, 0x0005}, + {0x00EC, 0x0007}, + {0x00F1, 0x007D}, + {0x00F2, 0x0008}, + {0x00F6, 0x007C}, + {0x00F8, 0x000C}, + {0x00F9, 0x0006}, + {0x00FC, 0x007E}, + {0x0393, 0x0013}, + {0x0394, 0x0010}, + {0x0398, 0x0019}, + {0x039B, 0x0014}, + {0x039E, 0x001A}, + {0x03A0, 0x0016}, + {0x03A3, 0x0018}, + {0x03A6, 0x0012}, + {0x03A8, 0x0017}, + {0x03A9, 0x0015}, + {0x20AC, 0x1B65} +}; + +// GSM Unicode +tSmsCharMapNode BIT7ToUCS2[] = { + {0x0000, 0x0040}, + {0x0001, 0x00A3}, + {0x0002, 0x0024}, + {0x0003, 0x00A5}, + {0x0004, 0x00E8}, + {0x0005, 0x00E9}, + {0x0006, 0x00F9}, + {0x0007, 0x00EC}, + {0x0008, 0x00F2}, + {0x0009, 0x00E7}, + {0x000B, 0x00D8}, + {0x000C, 0x00F8}, + {0x000E, 0x00C5}, + {0x000F, 0x00E5}, + {0x0010, 0x0394}, + {0x0011, 0x005F}, + {0x0012, 0x03A6}, + {0x0013, 0x0393}, + {0x0014, 0x039B}, + {0x0015, 0x03A9}, + {0x0016, 0x03A0}, + {0x0017, 0x03A8}, + {0x0018, 0x03A3}, + {0x0019, 0x0398}, + {0x001A, 0x039E}, + {0x001B, 0x00A0}, + {0x001C, 0x00C6}, + {0x001D, 0x00E6}, + {0x001E, 0x00DF}, + {0x001F, 0x00C9}, + {0x0024, 0x00A4}, + {0x0040, 0x00A1}, + {0x005B, 0x00C4}, + {0x005C, 0x00D6}, + {0x005D, 0x00D1}, + {0x005E, 0x00DC}, + {0x005F, 0x00A7}, + {0x0060, 0x00BF}, + {0x007B, 0x00E4}, + {0x007C, 0x00F6}, + {0x007D, 0x00F1}, + {0x007E, 0x00FC}, + {0x007F, 0x00E0} +}; +// GSM Unicode +tSmsCharMapNode BIT7EToUCS2[] = { + {0x000A, 0x000C}, + {0x0014, 0x005E}, + {0x0028, 0x007B}, + {0x0029, 0x007D}, + {0x002F, 0x005C}, + {0x003C, 0x005B}, + {0x003D, 0x007E}, + {0x003E, 0x005D}, + {0x0040, 0x007C}, + {0x0065, 0x20AC} +}; + +// map +int32_t SmsCharMapGetValue(tSmsCharMapNode *map, unsigned int size, unsigned short key) { + for (int i = 0; i < size; i++) { + if (map[i].key == key) + return map[i].value; + } + return -1; +} + + +#endif /* SMS_INC_CHRMAP_H_ */ \ No newline at end of file diff --git a/Inc/SmsEncoderDecoder.h b/Inc/SmsEncoderDecoder.h new file mode 100644 index 0000000..843e12f --- /dev/null +++ b/Inc/SmsEncoderDecoder.h @@ -0,0 +1,119 @@ +/* + * SMS.h + * + * Created on: Dec 4, 2020 + * Author: FICOM-IT LTD + */ + +//gitfix +#ifndef SMS_INC_SMS_H_ +#define SMS_INC_SMS_H_ + +#include +#include "stdint.h" +#include "stdbool.h" +#include "SmsUtfUtils.h" +#include "MemoryAllocationInterface.h" + +#define MAX_SMS_NR 32 + +typedef enum { + BIT7 = 0, // GSM + BIT8 = 1, // ASCII + UCS2 = 2, // Unicode + BIT8_HEX = 3, +} tEnumDCS; + +enum EnumUDL { + BIT7UDL = 160, + BIT8UDL = 140, + BIT8_HEX_UDL = 280, + UCS2UDL = 70 +}; + +enum EnumCSMIEI { + BIT8MIEI = 0, + BIT16MIEI = 8 +}; + +typedef struct { + unsigned int count; + char IEI; + char *IED; +} tPDUUDH; + + +typedef struct { + int count; + tPDUUDH *UDH; +} tUDHS; + +typedef struct { + unsigned int total; + char **Data; +} tUDS; + +typedef struct { + unsigned int Length; + char *Data; +} tUserRawDataSinglePackage; + +typedef struct { + unsigned int total; + char *Packages; +} tUserRawDataPackages; + +typedef struct { + unsigned int count; + unsigned int opacity; + char **PDU; +} tPDUS; + +typedef struct { + char *array; + unsigned int len; +} tByteArray; + +typedef struct { + char *SCA; + char *OA; + char *SCTS; + tUDHS *UDH; + char *UD; + int UDL; + + bool RP; + bool UDHI; + bool SRI; + bool MMS; + int MTI; + + char PID; + + tEnumDCS DCS; + bool TC; + int MC; + +} tSMS_Struct; + +#define SUB_STR_SIZE 512 + + +typedef struct { + enum EnumCSMIEI mCSMIEI; + char *mSCA; + bool mSRR; + bool mRD; + char *mVP; + int mCSMMR; + char temp[SUB_STR_SIZE]; + tMemAllocInterface *mem; +} tSmsPdu; + +void tSmsPdu_Init(tSmsPdu *env, tMemAllocInterface *mem); + +tSMS_Struct SmsPdu_Decode(tSmsPdu *env, const char *data, uint16_t len); + +tPDUS *SmsPdu_Encode(tSmsPdu *env, char *DA, char *UDC, tUDHS *udhs, tEnumDCS DCS); + +#endif /* SMS_INC_SMS_H_ */ \ No newline at end of file diff --git a/Inc/SmsEncoderDecoderPrivate.h b/Inc/SmsEncoderDecoderPrivate.h new file mode 100644 index 0000000..3e9bce2 --- /dev/null +++ b/Inc/SmsEncoderDecoderPrivate.h @@ -0,0 +1,85 @@ +// +// Created by xemon on 28.11.22. +// + +#ifndef UVEOS_ON_NATION_SMSENCODERDECODERPRIVATE_H +#define UVEOS_ON_NATION_SMSENCODERDECODERPRIVATE_H + +#include "SmsEncoderDecoder.h" + +//SMS-SUBMIT-PDU +/// SCA(Service Center Adress) +/// PDU-Type(Protocol Data Unit Type) +/// MR(Message Reference) +/// DA(Destination Adress) +/// PID(Protocol Identifier) +/// DCS(Data Coding Scheme) +/// VP(Validity Period) +/// UDL(User Data Length) +/// UD(User Data) + +tPDUS *tPDUDoEncoding(tSmsPdu *env, char *SCA, char *DA, char *UDC, tUDHS *udhs, tEnumDCS DCS); + +char *cSCADecoding(tSmsPdu *env, const char *data, int *EndIndex); + +char *cOADecoding(tSmsPdu *env, const char *data, int index, int *EndIndex); + +char *cSCTSDecoding(tSmsPdu *env, const char *data, int index); + +int iBCDDecoding(tSmsPdu *env, const char *data, int index, bool isMSB); + +tUDHS *tUDHDecoding(tSmsPdu *env, const char *data, int index); + +char *cUserDataDecoding(tSmsPdu *env, const char *data, int index, bool UDHI, tEnumDCS dcs, int *UDDL, uint16_t len); + +char *cBIT7Unpack(tSmsPdu *env, const char *data, int index, int Septets, int FillBits); + +char *cBIT7Decoding(tSmsPdu *env, char *BIT7Data, unsigned int size); + +int isBIT7Same(tSmsPdu *env, u_int16_t UCS2); + +int isGSMString(tSmsPdu *env, char *Data); + +tUDS *tUDCSplit(tSmsPdu *env, char *UDC, tUDHS *uhds, tEnumDCS DCS); + +int iGetUDHL(tSmsPdu *env, tUDHS *udhs); + +int iSeptetsLength(tSmsPdu *env, char *source); + +int iSeptetsToChars(tSmsPdu *env, char *source, int index, int septets); + +tUDHS *tUpdateUDH(tSmsPdu *env, tUDHS *udhs, int CSMMR, int total, int index); + +char *cSoloPDUEncoding(tSmsPdu *env, char *SCA, char *DA, char *UC, tUDHS *udhs, tEnumDCS DCS); + +char *cSCAEncoding(tSmsPdu *env, char *SCA); + +char *cPDUTypeEncoding(tSmsPdu *env, bool UDH); + +char *cMREncoding(tSmsPdu *env); + +char *cDAEncoding(tSmsPdu *env, char *DA); + +char *cPIDEncoding(tSmsPdu *env); + +char *cDCSEncoding(tSmsPdu *env, char *UD, tEnumDCS DCS); + +char *cUDEncoding(tSmsPdu *env, char *UD, tUDHS *udhs, tEnumDCS DCS); + +char *cUDHEncoding(tSmsPdu *env, tUDHS *udhs, int *UDHL); + +char *cUDCEncoding(tSmsPdu *env, char *UDC, int *UDCL, int UDHL, tEnumDCS DCS); + +tByteArray *tBIT7Encoding(tSmsPdu *env, char *UDC, int *Septets); + +char *cBIT7Pack(tSmsPdu *env, tByteArray *Bit7Array, int UDHL); + + +void deleteUDS(tSmsPdu *env, tUDS *uds); + +void deletePdus(tSmsPdu *env, tPDUS *pdus); + +void deleteUDHS(tSmsPdu *env, tUDHS *udhs); + + +#endif //UVEOS_ON_NATION_SMSENCODERDECODERPRIVATE_H \ No newline at end of file diff --git a/Inc/SmsUtfUtils.h b/Inc/SmsUtfUtils.h new file mode 100644 index 0000000..a1a5280 --- /dev/null +++ b/Inc/SmsUtfUtils.h @@ -0,0 +1,87 @@ +/* + * utf.h + * + * Created on: Dec 4, 2020 + * Author: FICOM-IT LTD + */ + +#ifndef SMS_INC_UTF_H_ +#define SMS_INC_UTF_H_ + + +#include +#include +#include + +typedef unsigned int UTF32; +typedef unsigned short UTF16; +typedef unsigned char UTF8; + +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16( + const UTF8 **sourceStart, const UTF8 *sourceEnd, + UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8( + const UTF16 **sourceStart, const UTF16 *sourceEnd, + UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF8toUTF32( + const UTF8 **sourceStart, const UTF8 *sourceEnd, + UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8( + const UTF32 **sourceStart, const UTF32 *sourceEnd, + UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32( + const UTF16 **sourceStart, const UTF16 *sourceEnd, + UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16( + const UTF32 **sourceStart, const UTF32 *sourceEnd, + UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags); + +bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +#ifdef __cplusplus +} +#endif + +u_int32_t next_char(unsigned char **string); + +const unsigned char *utf32toutf8(wchar_t *source, unsigned char *target, size_t size, int *len); + +unsigned char *utf16toutf8(unsigned short *source, unsigned char *target, size_t size, int *len); + +unsigned short *utf8toutf16(unsigned char *source, unsigned short *target, size_t size, int *len); + +int utf8len(unsigned char *string); + +int is_acsii(unsigned char *string); + +size_t utf8_get_size(unsigned char *source, size_t num); + +#endif /* SMS_INC_UTF_H_ */ \ No newline at end of file diff --git a/Src/SmsEncoderDecoder.c b/Src/SmsEncoderDecoder.c new file mode 100644 index 0000000..7d80d1b --- /dev/null +++ b/Src/SmsEncoderDecoder.c @@ -0,0 +1,1373 @@ +/* + * SMS.c + * + * Created on: Dec 4, 2020 + * Author: FICOM-IT LTD + */ +/* + * SMS.c + * + * Created on: Dec 4, 2020 + * Author: FICOM-IT LTD + */ + +//gitfix + +#include "SmsEncoderDecoderPrivate.h" +#include +#include +#include +#include + +static void SmsEncoderDecoder_mfree(tSmsPdu *env, void *pointer); + +static void *SmsEncoderDecoder_malloc(tSmsPdu *env, size_t size); + +// initialize PDU constants +void tSmsPdu_Init(tSmsPdu *env, tMemAllocInterface *mem) { + env->mCSMMR = 0; + env->mRD = false; + env->mSRR = false; + env->mSCA = ""; + env->mVP = ""; + env->mCSMIEI = BIT8MIEI; + env->mem = mem; +} + +void SmsEncoderDecoder_mfree(tSmsPdu *env, void *pointer) { + Mem_Free(env->mem, pointer); +} + +void *SmsEncoderDecoder_malloc(tSmsPdu *env, size_t size) { + return Mem_Alloc(env->mem, size); +} + +char *cSub_str(tSmsPdu *env, const char *str, int start, int size) { + memset(env->temp, '\0', SUB_STR_SIZE); + if (size > 0) + strncpy(env->temp, str + start, size); + else if (size < 0) + strcpy(env->temp, str + start); + + return env->temp; +} + +#pragma GCC push_options +#pragma GCC optimize ("O0") + +tSMS_Struct SmsPdu_Decode(tSmsPdu *env, const char *data, uint16_t len) { + + tSMS_Struct sms; + int end_index; + int PDUType; + sms.SCA = cSCADecoding(env, data, &end_index); + + PDUType = strtol(cSub_str(env, data, end_index, 2), NULL, 16); + end_index += 2; + + sms.RP = PDUType & (1 << 7) ? true : false; + sms.UDHI = PDUType & (1 << 6) ? true : false; + sms.SRI = PDUType & (1 << 5) ? true : false; + sms.MMS = PDUType & (1 << 2) ? false : true; + sms.MTI = PDUType & 3; + + sms.OA = cOADecoding(env, data, end_index, &end_index); + + sms.PID = strtol(cSub_str(env, data, end_index, 2), NULL, 16); + end_index += 2; + + int DCSType = strtol(cSub_str(env, data, end_index, 2), NULL, 16); + end_index += 2; + + sms.TC = DCSType & (1 << 5); + sms.DCS = (tEnumDCS) ((DCSType >> 2) & 3); + + if (DCSType & (1 << 4)) { + sms.MC = DCSType & 3; + } else { + sms.MC = -1; + } + sms.SCTS = cSCTSDecoding(env, data, end_index); + end_index += 14; + + if (sms.UDHI) { + sms.UDH = NULL; + sms.UDL = end_index; +// sms.UDH = tUDHDecoding(data, end_index + 2); + } else { + sms.UDH = NULL; + } + + sms.UD = cUserDataDecoding(env, data, end_index, sms.UDHI, sms.DCS, &sms.UDL, len); + + return sms; +} +//#pragma GCC pop_options + +char *cSCADecoding(tSmsPdu *env, const char *data, int *EndIndex) { + int len; + + char *result; + char *buf; + + len = strtol(cSub_str(env, data, 0, 2), NULL, 16); + if (len == 0) { + *EndIndex = 2; + return NULL; + } + + *EndIndex = (len + 1) * 2; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * len * 2); + //wmemset(result, '0', sizeof(char) * (len * 2 + 1)); + + buf = result; + len *= 2; + + if (strncmp(data + 2, "91", 2) == 0) { + sprintf(buf++, "+"); + } + + for (int i = 4; i < *EndIndex; + i += 2) { + sprintf(buf++, "%c", data[i + 1]); + sprintf(buf++, "%c", data[i]); + } + + if (result[strlen(result) - 1] == L'F') { + result[strlen(result) - 1] = L'\0'; + } + + return result; +} + +char *cOADecoding(tSmsPdu *env, const char *data, int index, int *EndIndex) { + int len; + char *result, *buf; + + len = strtol(cSub_str(env, data, index, 2), NULL, 16); + + if (len == 0) { + *EndIndex = index + 2; + return NULL; + } + + *EndIndex = index + 4 + len; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len + 2)); + //wmemset(result, 0, sizeof(char) * (len + 1)); + buf = result; + + if (strncmp(data + index + 2, "91", 2) == 0) { + sprintf(buf++, "+"); + } + + for (int i = 0; i < len; + i += 2) { + sprintf(buf++, "%c", data[index + i + 5]); + sprintf(buf++, "%c", data[index + i + 4]); + + } + + if (len % 2 != 0) { + result[strlen(result) - 1] = '\0'; + (*EndIndex)++; + } + return result; +} + +char *cSCTSDecoding(tSmsPdu *env, const char *data, int index) { + + char *result; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * 32); + sprintf(result, "20%02d-%02d-%02d %02d:%02d:%02d", + iBCDDecoding(env, data, index, 0), + iBCDDecoding(env, data, index + 2, 0), + iBCDDecoding(env, data, index + 4, 0), + iBCDDecoding(env, data, index + 6, 0), + iBCDDecoding(env, data, index + 8, 0), + iBCDDecoding(env, data, index + 10, 0) + ); + return result; +} + +int iBCDDecoding(tSmsPdu *env, const char *data, int index, bool isMSB) { + + int n1, n10; + + n1 = strtol(cSub_str(env, data, index, 1), NULL, 10); + n10 = strtol(cSub_str(env, data, index + 1, 1), NULL, 10); + + if (isMSB) { + if (n10 >= 8) + return -((n10 - 8) * 10 + n1); + else + return n10 * 10 + n1; + } else { + return n10 * 10 + n1; + } +} + +tUDHS *UDHDecoding(tSmsPdu *env, const char *data, int index) { + + int len; + tUDHS *result; + + len = strtol(cSub_str(env, data, index, 2), NULL, 16); + index += 2; + int i = 0; + + result = (tUDHS *) SmsEncoderDecoder_malloc(env, sizeof(tUDHS)); + result->UDH = (tPDUUDH *) SmsEncoderDecoder_malloc(env, sizeof(tPDUUDH) * len); + result->count = 0; + memset(result->UDH, 0, sizeof(tPDUUDH) * len); + + while (i < len) { + char IEI = strtol(cSub_str(env, data, index, 2), NULL, 16); + index += 2; + int IEDL = strtol(cSub_str(env, data, index, 2), NULL, 16); + index += 2; + char *IED = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (IEDL + 1)); + for (int j = 0; j < IEDL; + j++) { + IED[j] = strtol(cSub_str(env, data, index, 2), NULL, 16); + index += 2; + } + result->UDH[result->count].IEI = IEI; + result->UDH[result->count].IED = IED; + result->count++; + i += IEDL + 2; + } + + return result; +} + +char *cUserDataDecoding(tSmsPdu *env, const char *data, int index, bool UDHI, tEnumDCS dcs, int *UDDL, uint16_t len) { + char *result; + char *buf; + uint16_t idWrite = 0; + + int UDL = strtol(cSub_str(env, data, index, 2), NULL, 16); + index += 2; + + int UDHL = 0; + + if (UDHI) { + UDHL = strtol(cSub_str(env, data, index, 2), NULL, 16); + UDHL++; + index += UDHL << 1; + + } + + if (dcs == UCS2) { + int len = (UDL - UDHL) >> 1; + int utf8_len; + + *UDDL = len; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len * 3)); + buf = result; + u_int32_t code[2]; + + for (int i = 0; i < len; + i++) { + code[0] = strtol(cSub_str(env, data, (i << 2) + index, 4), NULL, 16); + code[1] = 0; + utf32toutf8((wchar_t *) code, (unsigned char *) buf, len * 3, &utf8_len); + buf += utf8_len; + } + + buf[0] = '\0'; + return result; + } else if (dcs == BIT7) { + int Septets = UDL - (UDHL * 8 + 6) / 7; + + *UDDL = Septets; + int FillBits = (UDHL * 8 + 6) / 7 * 7 - UDHL * 8; + return cBIT7Decoding(env, cBIT7Unpack(env, data, index, Septets, FillBits), Septets); + } else {// 8Bit + UDL -= UDHL; + *UDDL = UDL; + + uint16_t pos = UDL; + pos = pos * 2; + char res[pos]; + pos = len - pos; + uint16_t writeBits = UDL; + while (idWrite < sizeof(res)) { + res[idWrite] = data[pos]; + idWrite++; + pos++; + writeBits++; + } + result = res; + UDL -= UDHL; + return result; + } + + return 0; +} + +char *cBIT7Unpack(tSmsPdu *env, const char *data, int index, int Septets, int FillBits) { + char *result; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (Septets + 1)); + // 7-Bit + int PackLen = (Septets * 7 + FillBits + 7) / 8; + int n = 0; + int left = 0; + for (int i = 0; i < PackLen; i++) { + + int Order = (i + (7 - FillBits)) % 7; + int Value = strtol(cSub_str(env, data, (i << 1) + index, 2), NULL, 16); + if (i != 0 || FillBits == 0) { + result[n++] = ((Value << Order) + left) & 0x7F; + } + left = Value >> (7 - Order); + if (Order == 6) { + if (n == Septets) + break; + result[n++] = left; + left = 0; + } + } + + return result; +} + +char *cBIT7Decoding(tSmsPdu *env, char *BIT7Data, unsigned int size) { + char *result, *buf; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (size + 1)); + buf = result; + + for (int i = 0; i < size; + i++) { + u_int16_t key = BIT7Data[i]; + if (isBIT7Same(env, key)) { + sprintf(buf++, "%c", key); + } else if (SmsCharMapGetValue(BIT7ToUCS2, SMS_DC_EC_MAP_SIZE(BIT7ToUCS2), key) >= 0) { + u_int16_t value; + if (key == 0x1B) { + value = SmsCharMapGetValue(BIT7EToUCS2, SMS_DC_EC_MAP_SIZE(BIT7EToUCS2), BIT7Data[i + 1]); + if (i < size - 1 && value > 0) { + sprintf(buf++, "%c", value); + i++; + } else { + value = SmsCharMapGetValue(BIT7ToUCS2, SMS_DC_EC_MAP_SIZE(BIT7ToUCS2), key); + sprintf(buf++, "%c", value); + } + } else { ; + value = SmsCharMapGetValue(BIT7ToUCS2, SMS_DC_EC_MAP_SIZE(BIT7ToUCS2), key); + sprintf(buf++, "%c", value); + + } + } else { + sprintf(buf++, "?"); + } + + } + return result; + +} + +int isBIT7Same(tSmsPdu *env, u_int16_t UCS2) { + if ((UCS2 >= 0x61 && UCS2 <= 0x7A) || + (UCS2 >= 0x41 && UCS2 <= 0x5A) || + (UCS2 >= 0x25 && UCS2 <= 0x3F) || + (UCS2 >= 0x20 && UCS2 <= 0x23) || + UCS2 == 0x0A || UCS2 == 0x0D) { + return 1; + } + return 0; +} + + +tPDUS *SmsPdu_Encode(tSmsPdu *env, char *DA, char *UDC, tUDHS *udhs, tEnumDCS DCS) { + return tPDUDoEncoding(env, "", DA, UDC, udhs, DCS); +} +// +//////DA- DestenationAddress +//tPDUS *tPDUEncodingRAWData(tSmsEncoderDecoder *env,char *DestenationAddress, uint8_t *UserData,uint16_t LengthOfData){ +// sms_init(); +// return tPDUDoEncodingRAWData("", DestenationAddress, UserData, LengthOfData); +//} +//// +//// +//tPDUS *tPDUDoEncodingRAWData(tSmsEncoderDecoder *env,char *SCA,char *DestenationAddress, uint8_t *UserData,uint16_t LengthOfData){ +// tUDS *uds = tUDCSplitRAWData(UserData, LengthOfData); +// tPDUS *pdus; +// +// if (uds == NULL) +// return NULL; +// pdus = (tPDUS *) sms_malloc(env,sizeof(tPDUS)); +// pdus->count = 0; +// pdus->PDU = (char **) sms_malloc(env,sizeof(char *) * uds->total); +// +// if (tSmsEncoderDecoder *env,uds->total > 1){ +// int CSMMR = env->mCSMMR; +// if (++env->mCSMMR > 0xFFFF) +// env->mCSMMR = 0; +// for(int i = 0; i < uds->total; i++){ +// tUDHS *CSMUDH = tUpdateUDH(env,udhs, CSMMR, uds->total, i); +// pdus->PDU[i] = cSoloPDUEncoding(env,SCA, DA, uds->Data[i], CSMUDH, DCS); +// pdus->count++; +// } +// +// } +// else { +// pdus->PDU[0] = cSoloPDUEncoding(env,SCA, DA, uds->Data[0], udhs, DCS); +// pdus->count = 1; +// } +// +// return pdus; +//} + + +tPDUS *newPdus(tSmsPdu *env, uint16_t opacity) { + tPDUS *pdus = (tPDUS *) SmsEncoderDecoder_malloc(env, sizeof(tPDUS)); + pdus->count = 0; + pdus->opacity = opacity; + pdus->PDU = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *) * opacity); + return pdus; +} + +void deletePdus(tSmsPdu *env, tPDUS *pdus) { + for (unsigned int i = 0; i < pdus->opacity; + ++i) { + SmsEncoderDecoder_mfree(env, pdus->PDU[i]); + } + SmsEncoderDecoder_mfree(env, pdus); +} + +tPDUS *tPDUDoEncoding(tSmsPdu *env, char *SCA, char *DA, char *UDC, tUDHS *udhs, tEnumDCS DCS) { + tUDS *uds = tUDCSplit(env, UDC, udhs, DCS); + tPDUS *pdus; + + if (uds == NULL) { + return NULL; + } + + pdus = newPdus(env, uds->total); + + if (uds->total > 1) { + int CSMMR = env->mCSMMR; + + if (++env->mCSMMR > 0xFFFF) + env->mCSMMR = 0; + + for (int i = 0; i < uds->total; + i++) { + tUDHS *CSMUDH = tUpdateUDH(env, udhs, CSMMR, uds->total, i); + pdus->PDU[i] = cSoloPDUEncoding(env, SCA, DA, uds->Data[i], CSMUDH, DCS); + deleteUDHS(env, CSMUDH); + pdus->count++; + } + } else { + pdus->PDU[0] = cSoloPDUEncoding(env, SCA, DA, uds->Data[0], udhs, DCS); + pdus->count = 1; + } + + deleteUDS(env, uds); + + return pdus; +} + +int isGSMString(tSmsPdu *env, char *Data) { + + if (Data == NULL || strcmp(Data, "") == 0) + return 1; + + if (is_acsii((unsigned char *) Data) == 0) { + int len; + len = utf8len((unsigned char *) Data); + + u_int16_t *code = (u_int16_t *) SmsEncoderDecoder_malloc(env, sizeof(u_int16_t) * len); + utf8toutf16((unsigned char *) Data, code, len, &len); + + while (*code) { + if (!(isBIT7Same(env, *code) || SmsCharMapGetValue(UCS2ToBIT7, SMS_DC_EC_MAP_SIZE(UCS2ToBIT7), *code) >= 0)) + return 0; + code++; + } + + return 1; + } else + return 1; + +} + +char *newStringCopy(tSmsPdu *env, char *orgn, uint16_t length) { + char *newStr = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (length + 1)); + memcpy(newStr, orgn, length); + newStr[length] = 0; + return newStr; +} + +tUDS *newUDS(tSmsPdu *env) { + tUDS *uds = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + uds->total = 0; + uds->Data = (char **) SmsEncoderDecoder_malloc(env, MAX_SMS_NR * sizeof(char *)); + return uds; +} + +void deleteUDS(tSmsPdu *env, tUDS *uds) { + if (uds->Data) { + for (uint8_t idx = 0; idx < uds->total; + ++idx) { + SmsEncoderDecoder_mfree(env, uds->Data[idx]); + } + } + SmsEncoderDecoder_mfree(env, uds->Data); + SmsEncoderDecoder_mfree(env, uds); +} + + +tUDS *tUDCSplitUCS2(tSmsPdu *env, char *UDC, tUDHS *udhs, tEnumDCS DCS) { + int UDHL = iGetUDHL(env, udhs); + tUDS *result; + + uint16_t maximal_portion_length = UDHL > UCS2UDL ? 0 : UCS2UDL - UDHL; + + if (!maximal_portion_length) { + if (!(UDC == NULL || strcmp(UDC, "") == 0)) { + return NULL; + } + } + + uint16_t full_data_length = strlen((char *) UDC); + + if (full_data_length < maximal_portion_length) { + result = newUDS(env); + result->Data[result->total] = newStringCopy(env, UDC, full_data_length); + ++result->total; + + return result; + } + + if (UDHL == 0) + UDHL++; + if (env->mCSMIEI == BIT8MIEI) { + UDHL += 5; // 1byte + } else { + UDHL += 6; // 2byte + } + + maximal_portion_length = UDHL > UCS2UDL ? 0 : UCS2UDL - UDHL; + + if (!maximal_portion_length) { + return NULL; + } + + result = newUDS(env); + + uint16_t portion_length; + uint16_t left = full_data_length; + uint16_t begin_offset = 0; + + for (; + begin_offset < full_data_length; begin_offset += portion_length, left -= portion_length) { + + portion_length = left > maximal_portion_length ? maximal_portion_length : left; + + result->Data[result->total] = newStringCopy(env, UDC + begin_offset, portion_length); + + ++result->total; + } + + return result; +} + +tUDS *tUDCSplit(tSmsPdu *env, char *UDC, tUDHS *udhs, tEnumDCS DCS) { + int UDHL = iGetUDHL(env, udhs); + tUDS *result; + + if (DCS == BIT7) { + // 7-Bit + int room = BIT7UDL - (UDHL * 8 + 6) / 7; + if (room < 1) { + if (UDC == NULL || strcmp(UDC, "") == 0) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else + return NULL; + } + if (iSeptetsLength(env, UDC) <= room) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else { + if (UDHL == 0) + UDHL++; + if (env->mCSMIEI == BIT8MIEI) + UDHL += 5; + else + UDHL += 6; + room = BIT7UDL - (UDHL * 8 + 6) / 7; + if (room < 1) + return NULL; + + int i = 0; + int len = strlen(UDC); + + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->total = 0; + result->Data = (char **) SmsEncoderDecoder_malloc(env, MAX_SMS_NR * sizeof(char *)); + + while (i < len) { + int step = iSeptetsToChars(env, UDC, i, room); + if (i + step < len) { + result->Data[result->total] = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (step + 1)); + strcpy(result->Data[result->total++], cSub_str(env, UDC, i, step)); + } else { + result->Data[result->total] = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len - i + 1)); + strcpy(result->Data[result->total++], cSub_str(env, UDC, i, -1)); + } + + i += step; + + } + return result; + + } + } + if (DCS == BIT8) { // BIT8 + int room = BIT8UDL - UDHL; + if (room < 1) { + if (UDC == NULL || strcmp(UDC, "") == 0) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else + return NULL; + } + if (UDC == NULL || utf8len((unsigned char *) UDC) <= room) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else { + if (UDHL == 0) + UDHL++; + if (env->mCSMIEI == BIT8MIEI) + UDHL += 5; // 1byte + else + UDHL += 6; // 2byte + + room = BIT8UDL - UDHL; + if (room < 1) + return NULL; + + int len = utf8len((unsigned char *) UDC); + + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->total = 0; + result->Data = (char **) SmsEncoderDecoder_malloc(env, MAX_SMS_NR * sizeof(char *)); + int index = 0; + for (int i = 0; i < len; + i += room) { + int real_size; + if (i + room < len) { + real_size = utf8_get_size((unsigned char *) (UDC + index), room); + result->Data[result->total] = (char *) SmsEncoderDecoder_malloc(env, + sizeof(char) * (real_size + 1)); + strcpy(result->Data[result->total++], cSub_str(env, UDC, index, real_size)); + } else { + real_size = utf8_get_size((unsigned char *) (UDC + index), len - i); + result->Data[result->total] = (char *) SmsEncoderDecoder_malloc(env, + sizeof(char) * (real_size + 1)); + strcpy(result->Data[result->total++], cSub_str(env, UDC, index, -1)); + } + index += real_size; + } + return result; + } + + } + if (DCS == BIT8_HEX) { // BIT8 + int room = BIT8UDL - UDHL; + uint8_t hexRoom = room * 2; + + if (room < 1) { + if (UDC == NULL || strcmp(UDC, "") == 0) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else + return NULL; + } + uint8_t dataLen = strlen(UDC) / 2; + if (UDC == NULL || dataLen <= room) { + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->Data = (char **) SmsEncoderDecoder_malloc(env, sizeof(char *)); + result->total = 1; + result->Data[0] = UDC; + return result; + } else { + if (UDHL == 0) + UDHL++; + + if (env->mCSMIEI == BIT8MIEI) + UDHL += 5; // 1byte + else + UDHL += 6; // 2byte + + room = BIT8UDL - UDHL; + hexRoom = room * 2; + + if (room < 1) + return NULL; + + uint8_t hexDataLen = strlen(UDC) / 2; + + //init empty + result = (tUDS *) SmsEncoderDecoder_malloc(env, sizeof(tUDS)); + result->total = 0; + result->Data = (char **) SmsEncoderDecoder_malloc(env, MAX_SMS_NR * sizeof(char *)); + + //add pdus one by one + uint8_t lessThenFullRoom = 0; + int real_size; + + for (int index = 0; index < hexDataLen; + index += hexRoom) { + lessThenFullRoom = index + hexRoom < hexDataLen; + + real_size = lessThenFullRoom ? hexDataLen - index : hexRoom; + result->Data[result->total] = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (real_size + 1)); + strcpy(result->Data[result->total++], cSub_str(env, UDC, index, real_size)); + + } + return result; + } + + } + if (DCS == UCS2) { // UCS2 + return tUDCSplitUCS2(env, UDC, udhs, DCS); + } + return NULL; +} + + +// +//tUDS *tUDCSplitRAWData(tSmsEncoderDecoder *env,char *UserData, unsigned int UserDataLength){ +// tUserRawDataPackages *result; +// +// +// if (tSmsEncoderDecoder *env,BIT8UDL < 1){ +// +// if (tSmsEncoderDecoder *env,UserData == NULL || UserDataLength==NULL){ +// result = (tUserRawDataPackages *) sms_malloc(env,sizeof(tUserRawDataPackages)); +// result->Packages = (tUserRawDataSinglePackage *)sms_malloc(env,sizeof(tUserRawDataSinglePackage *)); +// result->total = 1; +// result->Packages[0].Data = UserData; +// result->Packages[0].Length = UserDataLength; +// return result; +// } +// else +// return NULL; +// } +// if (tSmsEncoderDecoder *env,UserData == NULL || UserDataLength <= BIT8UDL){ +// +// result = (tUserRawDataPackages *) sms_malloc(env,sizeof(tUserRawDataPackages)); +// result->Packages = (tUserRawDataSinglePackage **)sms_malloc(env,sizeof(tUserRawDataSinglePackage *)); +// result->total = 1; +// result->Packages[0].Data = UserData; +// result->Packages[0].Length = UserDataLength; +// +// return result; +// } +// else +// { +// uint tail = UserDataLength%BIT8UDL; +// +// result = (tUserRawDataPackages *) sms_malloc(env,sizeof(tUserRawDataPackages)); +// result->total = (UserDataLength / BIT8UDL) + tail?1:0; +// result->Packages = (tUserRawDataSinglePackage **)sms_malloc(env,sizeof(tUserRawDataSinglePackage *)*result->total); +// +// +// uint left = UserDataLength; +// for(int i = 0; i < result->total; ++i){ +// +// result->Packages[i].Length = leftPackages[i].Data = UserData; +// UserData = ((unsigned char*)UserData+result->Packages[i].Length); +// +// } +// +// return result; +// } +// +// +// +// +// return NULL; +//} + + +int iGetUDHL(tSmsPdu *env, tUDHS *udhs) { + if (udhs == NULL) + return 0; + + int UDHL = 1; + for (int i = 0; i < udhs->count; + i++) { + UDHL += strlen(udhs->UDH[i].IED) + 2; + } + return UDHL; +} + +int iSeptetsLength(tSmsPdu *env, char *source) { + if (source == NULL || strcmp(source, "") == 0) { + return 0; + } + int len = strlen(source); + while (*source) { + u_int16_t code = (u_int16_t) *source; + if (SmsCharMapGetValue(UCS2ToBIT7, SMS_DC_EC_MAP_SIZE(UCS2ToBIT7), code) > 0xFF) { + len++; + } + source++; + } + return len; +} + +int iSeptetsToChars(tSmsPdu *env, char *source, int index, int septets) { + if (source == NULL || strcmp(source, "") == 0) + return 0; + int count = 0; + int i; + + for (i = index; i < strlen(source); i++) { + u_int16_t code = (u_int16_t) source[i]; + if (SmsCharMapGetValue(UCS2ToBIT7, SMS_DC_EC_MAP_SIZE(UCS2ToBIT7), code) > 0xFF) + count++; + + if (++count >= septets) { + if (count == septets) + i++; + break; + } + } + return i - index; +} + +tUDHS *newUDHS(tSmsPdu *env, int count) { + tUDHS *udhs = (tUDHS *) SmsEncoderDecoder_malloc(env, sizeof(tUDHS)); + udhs->UDH = (tPDUUDH *) SmsEncoderDecoder_malloc(env, sizeof(tPDUUDH) * (count)); + udhs->count = count; + return udhs; +} + +void deleteUDHS(tSmsPdu *env, tUDHS *udhs) { + for (uint16_t idx = 0; idx < udhs->count; + ++idx) { + SmsEncoderDecoder_mfree(env, udhs->UDH->IED); + } + SmsEncoderDecoder_mfree(env, udhs->UDH); + SmsEncoderDecoder_mfree(env, udhs); +} + +void copytPDUUDH(tSmsPdu *env, tPDUUDH *target, tPDUUDH *source) { + memcpy(target, source, sizeof(tPDUUDH)); + + if (source->IED) { + target->IED = SmsEncoderDecoder_malloc(env, sizeof(char) * target->count); + memcpy(target->IED, source->IED, sizeof(target->count)); + } + +} + +void copytPDUUDHS(tSmsPdu *env, tPDUUDH *target, tPDUUDH *source, uint16_t count) { + for (uint16_t i = 0; i < count; + ++i) { + copytPDUUDH(env, target + count, source + count); + } +} + +tUDHS *tUpdateUDH(tSmsPdu *env, tUDHS *udhs, int CSMMR, int total, int index) { + + tUDHS *result; + if (udhs == NULL || udhs->count == 0) { + result = newUDHS(env, 1); + } else { + result = newUDHS(env, udhs->count + 1); + //UDH + copytPDUUDHS(env, result->UDH + 1, udhs->UDH, udhs->count); + } + + if (env->mCSMIEI == BIT8MIEI) { + result->UDH[0].IED = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * 3); + result->UDH[0].count = 3; + result->UDH[0].IED[0] = CSMMR & 0xFF; + result->UDH[0].IED[1] = total; + result->UDH[0].IED[2] = index + 1; + result->UDH[0].IEI = 0; + } else { + result->UDH[0].IED = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * 4); + result->UDH[0].count = 4; + result->UDH[0].IED[0] = (CSMMR >> 8) & 0xFF; + result->UDH[0].IED[1] = CSMMR & 0xFF; + result->UDH[0].IED[2] = total; + result->UDH[0].IED[3] = index + 1; + result->UDH[0].IEI = 8; + } + + return result; +} + +char *cSoloPDUEncoding(tSmsPdu *env, char *SCA, char *DA, char *UC, tUDHS *udhs, tEnumDCS DCS) { + char *result; + char *buf, *ret; + int index; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * 400); + buf = result; + + ret = cSCAEncoding(env, SCA); + index = strlen(ret); + sprintf(buf, "%s", ret); + buf += index; + SmsEncoderDecoder_mfree(env, ret); + + bool hasUDH = !(udhs == NULL || udhs->count == 0); + ret = cPDUTypeEncoding(env, hasUDH); + sprintf(buf, "%s", ret); + buf += strlen(ret); + SmsEncoderDecoder_mfree(env, ret); + + ret = cMREncoding(env); + sprintf(buf, "%s", ret); + buf += strlen(ret); + + ret = cDAEncoding(env, DA); + sprintf(buf, "%s", ret); + buf += strlen(ret); + SmsEncoderDecoder_mfree(env, ret); + + ret = cPIDEncoding(env); + sprintf(buf, "%s", ret); + buf += strlen(ret); + + + ret = cDCSEncoding(env, UC, DCS); + sprintf(buf, "%s", ret); + buf += strlen(ret); + sprintf(buf, "%s", env->mVP); + buf += strlen(env->mVP); + + ret = cUDEncoding(env, UC, udhs, DCS); + sprintf(buf, "%s", ret); + SmsEncoderDecoder_mfree(env, ret); + + return result; +} + +char *cSoloPDUEncodingRAWData(tSmsPdu *env, char *SCA, char *DA, char *UserData, uint UserDataLength, + tUDHS *udhs) { + char *result; + char *buf, *ret; + int index; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * 400); + buf = result; + + ret = cSCAEncoding(env, SCA); + index = strlen(ret); + sprintf(buf, "%s", ret); + + buf += index; + if (udhs == NULL || udhs->count == 0) { + ret = cPDUTypeEncoding(env, false); + sprintf(buf, "%s", ret); + buf += strlen(ret); + } else { + ret = cPDUTypeEncoding(env, true); + sprintf(buf, "%s", ret); + buf += strlen(ret); + } + + + ret = cMREncoding(env); + sprintf(buf, "%s", ret); + + + buf += strlen(ret); + ret = cDAEncoding(env, DA); + sprintf(buf, "%s", ret); + + + buf += strlen(ret); + ret = cPIDEncoding(env); + sprintf(buf, "%s", ret); + + +// buf += strlen(ret); +// ret = cDCSEncoding(env,UC, DCS); +// sprintf(buf, "%s", ret); +// +// +// buf += strlen(ret); +// sprintf(buf, "%s", env->mVP); +// +// +// buf += strlen(env->mVP); +// ret = cUDEncoding(env,UC, udhs, DCS); +// sprintf(buf, "%s", ret); + + return result; +} + + +char *cSCAEncoding(tSmsPdu *env, char *SCA) { + + char *result; + if (SCA == NULL || strcmp(SCA, "") == 0) { + // SMS center on SIM or set AT+CSCA command + return newStringCopy(env, "00", 2); + } + + + char *buf; + int len; + len = strlen(SCA); + result = (char *) SmsEncoderDecoder_malloc(env, (len + 5) * sizeof(char)); + buf = result; + + int index = 0; + if (SCA[0] == '+') { + sprintf(buf, "%02X", len / 2 + 1); + buf += 2; + sprintf(buf, "91"); + buf += 2; + index = 1; + } else { + sprintf(buf, "%02X", len / 2 + 1); + buf += 2; + sprintf(buf, "81"); + buf += 2; + } + // SCA + for (; index < len; index += 2) { + if (index == len - 1) { + // “F” + sprintf(buf++, "F"); + sprintf(buf++, "%c", SCA[index]); + + } else { + sprintf(buf++, "%c", SCA[index + 1]); + sprintf(buf++, "%c", SCA[index]); + } + } + + return result; +} + +char *cPDUTypeEncoding(tSmsPdu *env, bool UDH) { + // Message Type Indicator + // 01 SMS-SUBMIT(MS -> SMSC) + int PDUType = 0x01; + char *result; + result = (char *) SmsEncoderDecoder_malloc(env, 3 * sizeof(char)); + + // User Data Header Indicator + if (UDH) { + PDUType |= 0x40; + } + // Validity Period Format + if (strlen(env->mVP) == 2) { + // VP + PDUType |= 0x10; + } else if (strlen(env->mVP) == 14) { + // VP semi-octet + PDUType |= 0x18; + } + + // Status Report Request + if (env->mSRR) { + // 请求状态报告 + PDUType |= 0x20; + } + + // Reject Duplicate + if (env->mRD) { + PDUType |= 0x04; + } + sprintf(result, "%02X", PDUType); + return result; +} + +char *cMREncoding(tSmsPdu *env) { + return "00"; +} + +char *cDAEncoding(tSmsPdu *env, char *DA) { + if (DA == NULL || strcmp(DA, "") == 0) { + return newStringCopy(env, "0080", 4); + } + char *result, *buf; + int len = strlen(DA); + int index = 0; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len + 5)); + buf = result; + + if (DA[0] == '+') { + sprintf(buf, "%02X", len - 1); + buf += 2; + sprintf(buf, "91"); + buf += 2; + index = 1; + } else { + sprintf(buf, "%02X", len); + buf += 2; + sprintf(buf, "81"); + buf += 2; + index = 0; + } + + for (; index < len; index += 2) { + if (index == len - 1) { + sprintf(buf++, "F"); + sprintf(buf++, "%c", DA[index]); + } else { + sprintf(buf++, "%c", DA[index + 1]); + sprintf(buf++, "%c", DA[index]); + } + } + return result; + +} + +char *cPIDEncoding(tSmsPdu *env) { + return "00"; +} + +char *cDCSEncoding(tSmsPdu *env, char *UD, tEnumDCS DCS) { + if (DCS == BIT7) { + // 7-Bit + return "00"; + } + if (DCS == BIT8) { + //8-bit + return "04"; + } + if (DCS == BIT8_HEX) { + //8-bit + return "04"; + } + if (DCS == UCS2) { + // UCS2 + return "08"; + } +} + +char *cUDEncoding(tSmsPdu *env, char *UD, tUDHS *udhs, tEnumDCS DCS) { + int UDHL; + + char *result; + + char *header = cUDHEncoding(env, udhs, &UDHL); + + int UDCL; + char *body; + + body = cUDCEncoding(env, UD, &UDCL, UDHL, DCS); + + int UDL; + if (DCS == BIT7) { + // 7-Bit + UDL = (UDHL * 8 + 6) / 7 + UDCL; + } else { + // UCS2 8-Bit + UDL = UDHL + UDCL; + } + + int len = strlen(header) + strlen(body) + 2; + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len + 1)); + sprintf(result, "%02X%s%s", UDL, header, body); + + SmsEncoderDecoder_mfree(env, header); + SmsEncoderDecoder_mfree(env, body); + + return result; + +} + +char *cUDHEncoding(tSmsPdu *env, tUDHS *udhs, int *UDHL) { + + *UDHL = 0; + + if (udhs == NULL || udhs->count == 0) + return newStringCopy(env, "", 0); + + for (int i = 0; i < udhs->count; + i++) { + *UDHL += udhs->UDH[i].count + 2; + } + + char *result; + char *buf; + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * ((*UDHL + 1) * 2 + 1)); + buf = result; + + sprintf(buf, "%02X", *UDHL); + buf += 2; + for (int i = 0; i < udhs->count; + i++) { + sprintf(buf, "%02X", udhs->UDH[i].IEI); + buf += 2; + sprintf(buf, "%02X", udhs->UDH[i].count); + buf += 2; + for (int j = 0; j < udhs->UDH[i].count; + j++) { + sprintf(buf, "%02X", udhs->UDH[i].IED[j]); + buf += 2; + } + + } + (*UDHL)++; + return result; + +} + +char *cUDCEncoding(tSmsPdu *env, char *UDC, int *UDCL, int UDHL, tEnumDCS DCS) { + if (UDC == NULL || strcmp(UDC, "") == 0) { + *UDCL = 0; + return ""; + } + + if (DCS == BIT7) { // 7-Bit + return cBIT7Pack(env, tBIT7Encoding(env, UDC, UDCL), UDHL); + } + if (DCS == BIT8) { // 8-bit + int len = utf8len((unsigned char *) UDC); + //int len2; +// unsigned short *code; + + //code = (unsigned short *) sms_malloc(env,sizeof(unsigned short) * len); + //utf8toutf16((unsigned char *) UDC, code, len, &len2); + *UDCL = len; + char *result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (*UDCL * 2 + 1)); + char *buf = result; + + for (int i = 0; i < len; + i++) { + sprintf(buf, "%02X", UDC[i]); //code[i]); + buf += 2; + } +// sms_mfree(env,code); + return result; + } + if (DCS == BIT8_HEX) { // 8-bit hex data + int len = strlen(UDC); + *UDCL = len / 2; + char *result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len + 1)); + memcpy(result, UDC, len); + + return result; + } + if (DCS == UCS2) { // UCS2 + int len = utf8len((unsigned char *) UDC); + int len2; + unsigned short *code; + + code = (unsigned short *) SmsEncoderDecoder_malloc(env, sizeof(unsigned short) * len); + utf8toutf16((unsigned char *) UDC, code, len, &len2); + *UDCL = len * 2; + char *result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (*UDCL * 2 + 1)); + char *buf = result; + + for (int i = 0; i < len; + i++) { + sprintf(buf, "%04X", code[i]); + buf += 4; + } + SmsEncoderDecoder_mfree(env, code); + return result; + } + return ""; +} + +tByteArray *tBIT7Encoding(tSmsPdu *env, char *UDC, int *Septets) { + tByteArray *result; + + int len = strlen(UDC); + + result = (tByteArray *) SmsEncoderDecoder_malloc(env, sizeof(tByteArray)); + result->len = 0; + result->array = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (len * 2 + 1)); + *Septets = 0; + + for (int i = 0; i < len; + i++) { + u_int16_t code = (u_int16_t) UDC[i]; + if (isBIT7Same(env, code)) { + result->array[(*Septets)++] = code; + } else { + u_int16_t value = SmsCharMapGetValue(UCS2ToBIT7, SMS_DC_EC_MAP_SIZE(UCS2ToBIT7), code); + if (value >= 0) { + if (value > 0xFF) { + result->array[(*Septets)++] = value >> 8; + result->array[(*Septets)++] = value & 0xFF; + } else { + result->array[(*Septets)++] = value; + } + } else { + result->array[(*Septets)++] = (u_int16_t) '?'; + } + } + } + result->len = *Septets; + + return result; +} + +char *cBIT7Pack(tSmsPdu *env, tByteArray *Bit7Array, int UDHL) { + // 7Bit + int fillBits = (UDHL * 8 + 6) / 7 * 7 - (UDHL * 8); + + int len = Bit7Array->len; + int packLen = (len * 7 + fillBits + 7) / 8; + char *result; + char *buf; + + result = (char *) SmsEncoderDecoder_malloc(env, sizeof(char) * (packLen * 2 + 1)); + buf = result; + + int left = 0; + for (int i = 0; i < len; + i++) { + int32_t Value = Bit7Array->array[i]; + int32_t index = (i + 8 - fillBits) % 8; + if (index == 0) { + left = Value; + } else { + int32_t n = ((Value << (8 - index)) | left) & 0xFF; + sprintf(buf, "%02X", (unsigned int) n); + buf += 2; + left = Value >> index; + } + } + + + if ((len * 7 + fillBits) % 8 != 0) { + sprintf(buf, "%02X", left); + buf += 2; + } + buf[0] = '\0'; + return result; +} +#pragma GCC pop_options diff --git a/Src/SmsUtfUtils.c b/Src/SmsUtfUtils.c new file mode 100644 index 0000000..03e8c0f --- /dev/null +++ b/Src/SmsUtfUtils.c @@ -0,0 +1,615 @@ +/* + * utf.c + * + * Created on: Dec 5, 2020 + * Author: FICOM-IT LTD + */ + + +#include "SmsUtfUtils.h" +#include +#include +#include + +static const int halfShift = 10; +/* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF +#define false 0 +#define true 1 + +ConversionResult ConvertUTF32toUTF16( + const UTF32 **sourceStart, const UTF32 *sourceEnd, + UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32 *source = *sourceStart; + UTF16 *target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; + break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16) ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; + break; + } + ch -= halfBase; + *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +ConversionResult ConvertUTF16toUTF32( + const UTF16 **sourceStart, const UTF16 *sourceEnd, + UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16 *source = *sourceStart; + UTF32 *target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; + break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +static const char trailingBytesForUTF8[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 +}; + +static const UTF32 offsetsFromUTF8[6] = {0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL}; + +static const UTF8 firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC}; + +ConversionResult ConvertUTF16toUTF8( + const UTF16 **sourceStart, const UTF16 *sourceEnd, + UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16 *source = *sourceStart; + UTF8 *target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16 *oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32) 0x80) { + bytesToWrite = 1; + } else if (ch < (UTF32) 0x800) { + bytesToWrite = 2; + } else if (ch < (UTF32) 0x10000) { + bytesToWrite = 3; + } else if (ch < (UTF32) 0x110000) { + bytesToWrite = 4; + } else { + bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; + result = targetExhausted; + break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 3: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 2: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 1: + *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +static bool isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source + length; + switch (length) { + default: + return false; + /* Everything else falls through when "true"... */ + case 4: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: + if ((a = (*--srcptr)) > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: + if (a < 0xA0) return false; + break; + case 0xED: + if (a > 0x9F) return false; + break; + case 0xF0: + if (a < 0x90) return false; + break; + case 0xF4: + if (a > 0x8F) return false; + break; + default: + if (a < 0x80) return false; + } + + case 1: + if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +bool isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source] + 1; + if (source + length > sourceEnd) { + return false; + } + return isLegalUTF8(source, length); +} + +ConversionResult ConvertUTF8toUTF16( + const UTF8 **sourceStart, const UTF8 *sourceEnd, + UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8 *source = *sourceStart; + UTF16 *target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; + break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead + 1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: + ch += *source++; + ch <<= 6; /* remember, illegal UTF-8 */ + case 4: + ch += *source++; + ch <<= 6; /* remember, illegal UTF-8 */ + case 3: + ch += *source++; + ch <<= 6; + case 2: + ch += *source++; + ch <<= 6; + case 1: + ch += *source++; + ch <<= 6; + case 0: + ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead + 1); /* Back up source pointer! */ + result = targetExhausted; + break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead + 1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16) ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead + 1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead + 1); /* Back up source pointer! */ + result = targetExhausted; + break; + } + ch -= halfBase; + *target++ = (UTF16) ((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16) ((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +ConversionResult ConvertUTF32toUTF8( + const UTF32 **sourceStart, const UTF32 *sourceEnd, + UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32 *source = *sourceStart; + UTF8 *target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32) 0x80) { + bytesToWrite = 1; + } else if (ch < (UTF32) 0x800) { + bytesToWrite = 2; + } else if (ch < (UTF32) 0x10000) { + bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { + bytesToWrite = 4; + } else { + bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; + result = targetExhausted; + break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 3: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 2: + *--target = (UTF8) ((ch | byteMark) & byteMask); + ch >>= 6; + case 1: + *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +ConversionResult ConvertUTF8toUTF32( + const UTF8 **sourceStart, const UTF8 *sourceEnd, + UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8 *source = *sourceStart; + UTF32 *target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (source + extraBytesToRead >= sourceEnd) { + result = sourceExhausted; + break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead + 1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: + ch += *source++; + ch <<= 6; + case 4: + ch += *source++; + ch <<= 6; + case 3: + ch += *source++; + ch <<= 6; + case 2: + ch += *source++; + ch <<= 6; + case 1: + ch += *source++; + ch <<= 6; + case 0: + ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead + 1); /* Back up the source pointer! */ + result = targetExhausted; + break; + } + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead + 1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +const unsigned char *utf32toutf8(wchar_t *source, unsigned char *target, size_t size, int *len) { + + wchar_t *s_start; + unsigned char *t_start; + + s_start = source; + t_start = target; + + if (ConvertUTF32toUTF8((const UTF32 **) &s_start, (UTF32 *) s_start + wcslen(source), (UTF8 **) &t_start, + (UTF8 *) t_start + size, strictConversion) == conversionOK) { + *len = t_start - target; + } else { + *len = 0; + } + target[*len] = '\0'; + return (const unsigned char *) target; +} + + +unsigned char *utf16toutf8(unsigned short *source, unsigned char *target, size_t size, int *len) { + + unsigned short *s_start; + unsigned char *t_start; + + s_start = source; + t_start = target; + + if (ConvertUTF16toUTF8((const UTF16 **) &s_start, (UTF16 *) s_start + strlen((const char *) source) / 2, + (UTF8 **) &t_start, (UTF8 *) t_start + size, strictConversion) == conversionOK) { + *len = t_start - target; + } else { + *len = 0; + } + target[*len] = '\0'; + return target; +} + +unsigned short *utf8toutf16(unsigned char *source, unsigned short *target, size_t size, int *len) { + unsigned char *s_start; + unsigned short *t_start; + + s_start = source; + t_start = target; + + if (ConvertUTF8toUTF16((const UTF8 **) &s_start, s_start + strlen((const char *) source), &t_start, t_start + size, + strictConversion) == conversionOK) { + *len = t_start - target; + } else { + *len = 0; + } + + return target; +} + +u_int32_t next_char(unsigned char **string) { + + int len = strlen((const char *) *string); + unsigned char ch[4]; + + if (len < 4) { + for (int i = 0; i < len; i++) + ch[i] = (*string)[i]; + } else { + ch[0] = (*string)[0]; + ch[1] = (*string)[1]; + ch[2] = (*string)[2]; + ch[3] = (*string)[3]; + } + + if (ch[0] < 0x80) { + *string = (*string + 1); + return ch[0]; + } else if (ch[0] >= 0xc0 && ch[0] <= 0xdf) { + *string = (*string + 2); + return ch[1] << 8 | ch[0]; + } else if (ch[0] >= 0xe0 && ch[0] <= 0xef) { + *string = (*string + 3); + return ch[2] << 16 | ch[1] << 8 | ch[0]; + } else if (ch[0] >= 0xf0 && ch[0] <= 0xf7) { + *string = (*string + 4); + return ch[3] << 24 | ch[2] << 16 | ch[1] << 8 | ch[0]; + } + + return *(u_int32_t *) ch; +} + + +int utf8len(unsigned char *string) { + unsigned char *end; + int ret = 0; + + end = string + strlen((const char *) string); + while (string < end) { + next_char(&string); + ret++; + } + return ret; +} + +int is_acsii(unsigned char *string) { + while (*string) { + if (*string >= 0x80) + return 0; + string++; + } + return 1; +} + +size_t utf8_get_size(unsigned char *source, size_t num) { + size_t ret = 0; + + unsigned char *cur = source; + while (num-- && *cur) { + next_char(&cur); + } + ret = cur - source; + + return ret; +} + + + diff --git a/modular.json b/modular.json new file mode 100644 index 0000000..69e5948 --- /dev/null +++ b/modular.json @@ -0,0 +1,17 @@ +{ + "dep": [ + { + "type": "git", + "provider": "Smart_Components_Aurus", + "repo": "MemoryAllocationInterface" + } + ], + "cmake": { + "inc_dirs": [ + "Inc" + ], + "srcs": [ + "Src/**.c" + ] + } +} \ No newline at end of file