diff options
author | Aki Niemi <aki.niemi@nokia.com> | 2009-09-14 14:34:00 +0300 |
---|---|---|
committer | Aki Niemi <aki.niemi@nokia.com> | 2009-09-14 14:34:00 +0300 |
commit | dec66954b6e4569f644f3e1f4a0a5a02f30662d4 (patch) | |
tree | 9723ab205d37726635afd8f04c8a1354ae5f4604 /gisi/iter.c | |
parent | ffaba2b637f403af238551d5ec87d9955ce5a23a (diff) | |
download | ofono-dec66954b6e4569f644f3e1f4a0a5a02f30662d4.tar.gz |
gisi: Add ISI sub-block iterator
Diffstat (limited to 'gisi/iter.c')
-rw-r--r-- | gisi/iter.c | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/gisi/iter.c b/gisi/iter.c new file mode 100644 index 00000000..dfc6dfa8 --- /dev/null +++ b/gisi/iter.c @@ -0,0 +1,155 @@ +/* + * This file is part of oFono - Open Source Telephony + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: RĂ©mi Denis-Courmont <remi.denis-courmont@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <glib.h> +#include <arpa/inet.h> + +#include "iter.h" + +static inline void bcd_to_mccmnc(const uint8_t *bcd, char *mcc, char *mnc) +{ + mcc[0] = '0' + (bcd[0] & 0x0F); + mcc[1] = '0' + ((bcd[0] & 0xF0) >> 4); + mcc[2] = '0' + (bcd[1] & 0x0F); + mcc[3] = '\0'; + + mnc[0] = '0' + (bcd[2] & 0x0F); + mnc[1] = '0' + ((bcd[2] & 0xF0) >> 4); + mnc[2] = (bcd[1] & 0xF0) == 0xF0 ? '\0' : '0' + + (bcd[1] & 0xF0); + mnc[3] = '\0'; +} + +bool g_isi_sb_iter_is_valid(GIsiSubBlockIter *iter) +{ + if (!iter || iter->end - iter->start < 2) + return false; + + if (iter->start + iter->start[1] > iter->end) + return false; + + return true; +} + +uint8_t g_isi_sb_iter_get_id(GIsiSubBlockIter *iter) +{ + return iter->start[0]; +} + +uint8_t g_isi_sb_iter_get_len(GIsiSubBlockIter *iter) +{ + return iter->start[1]; +} + +bool g_isi_sb_iter_get_byte(GIsiSubBlockIter *iter, uint8_t *byte, int pos) +{ + if (pos > iter->start[1] || iter->start + pos > iter->end) + return false; + + *byte = iter->start[pos]; + return true; +} + +bool g_isi_sb_iter_get_word(GIsiSubBlockIter *iter, uint16_t *word, int pos) +{ + uint16_t val; + + if (pos + 1 > iter->start[1]) + return false; + + memcpy(&val, iter->start + pos, sizeof(uint16_t)); + *word = ntohs(val); + return true; +} + +bool g_isi_sb_iter_get_dword(GIsiSubBlockIter *iter, uint32_t *dword, + int pos) +{ + uint32_t val; + + if (pos + 3 > iter->start[1]) + return false; + + memcpy(&val, iter->start + pos, sizeof(uint32_t)); + *dword = ntohl(val); + return true; +} + +bool g_isi_sb_iter_get_oper_code(GIsiSubBlockIter *iter, char *mcc, + char *mnc, int pos) +{ + if (pos + 2 > iter->start[1]) + return false; + + bcd_to_mccmnc(iter->start + pos, mcc, mnc); + return true; +} + +bool g_isi_sb_iter_get_alpha_tag(GIsiSubBlockIter *iter, char **utf8, + int pos) +{ + uint8_t *ucs2 = NULL; + int len = 0; + + if (pos > iter->start[1]) + return false; + + len = iter->start[pos] * 2; /* Alpha tags are UCS-2 */ + + if (!utf8 || len == 0 || pos + 1 + len > iter->start[1]) + return false; + + ucs2 = iter->start + pos + 1; + *utf8 = g_convert((const char *)ucs2, len, "UTF-8//TRANSLIT", "UCS-2BE", + NULL, NULL, NULL); + return utf8 != NULL; +} + +bool g_isi_sb_iter_init(const void restrict *data, size_t len, GIsiSubBlockIter *iter) +{ + if (!iter || !data || len == 0) + return false; + + iter->start = (uint8_t *)data; + iter->end = iter->start + len; + + return true; +} + +bool g_isi_sb_iter_next(GIsiSubBlockIter *iter) +{ + uint8_t len = iter->start[1] == 0 ? 2 : iter->start[1]; + + if (iter->start + len > iter->end) + return false; + + iter->start += len; + return true; +} |