diff --git a/Makefile.am b/Makefile.am
index ac138f9..2bc857b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -6,8 +6,8 @@ AM_LDFLAGS = @LIBNFC_LIBS@
lib_LTLIBRARIES = libfreefare.la
-libfreefare_la_SOURCES = mifare_classic.c mad.c
-libfreefare_la_HEADERS = mifare_classic.h mad.h
+libfreefare_la_SOURCES = mifare_classic.c mad.c mifare_application.c
+libfreefare_la_HEADERS = mifare_classic.h mad.h mifare_application.h
libfreefare_ladir = $(includedir)
pkgconfigdir = $(libdir)/pkgconfig
diff --git a/mifare_application.c b/mifare_application.c
new file mode 100644
index 0000000..f3dccda
--- /dev/null
+++ b/mifare_application.c
@@ -0,0 +1,170 @@
+/*-
+ * Copyright (C) 2009, Romain Tartiere, Romuald Conty.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or (at your
+ * option) any later version.
+ *
+ * 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 Lesser General Public License
+ * along with this program. If not, see
+ *
+ * $Id: mad.c 81 2009-12-21 00:40:07Z romain.tartiere $
+ */
+
+/*
+ * This implementation was written based on information provided by the
+ * following document:
+ *
+ * /dev/brain
+ */
+#include
+
+#include
+
+#define FIRST_SECTOR 1
+
+int aidcmp (const MadAid left, const MadAid right);
+size_t count_aids (const Mad mad, const MadAid aid);
+
+/*
+ * Get the number of sectors allocated in the MAD for the provided application.
+ */
+size_t
+count_aids (const Mad mad, const MadAid aid)
+{
+ size_t result = 0;
+
+ MifareSectorNumber s_max = (mad_get_version (mad) == 1) ? 0x0f : 0x27;
+
+ /* Count application sectors */
+ MadAid c_aid;
+ for (MifareSectorNumber s = FIRST_SECTOR; s <= s_max; s++) {
+ mad_get_aid (mad, s, &c_aid);
+ if (0 == aidcmp (aid, c_aid)) {
+ result++;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Compare two application identifiers.
+ */
+inline int
+aidcmp (const MadAid left, const MadAid right)
+{
+ return ((left.function_cluster_code - right.function_cluster_code) << 8) | (left.application_code - right.application_code);
+}
+
+
+/*
+ * Card publisher functions (MAD owner).
+ */
+
+/*
+ * Allocates a new application into a MAD.
+ */
+MifareSectorNumber *
+mifare_application_alloc (Mad mad, MadAid aid, size_t size)
+{
+ /*
+ * Ensure the card does not already have the application registered.
+ */
+ MifareSectorNumber *found;
+ if ((found = mifare_application_find (mad, aid))) {
+ free (found);
+ return NULL;
+ }
+
+ MifareSectorNumber *res = malloc (sizeof (*res) * (size+1));
+ res[size] = 0;
+
+ /*
+ * Ensure the remaining free space is suficient before destroying the MAD.
+ */
+ MadAid free_aid = { 0x00, 0x00 };
+ MifareSectorNumber *free_aids = mifare_application_find (mad, free_aid);
+ if (!free_aids)
+ return NULL;
+
+
+ for (int c = 0; c < size; c++) {
+ if (free_aids[c]) {
+ res[c] = free_aids[c];
+ } else {
+ free (res);
+ res = NULL;
+ break;
+ }
+ }
+
+ free (free_aids);
+
+ if (res) {
+ /* Update the MAD */
+ for (int c = 0; c < size; c++)
+ mad_set_aid (mad, res[c], aid);
+ }
+
+ /* Return the list of allocated sectors */
+ return res;
+}
+
+/*
+ * Remove an application from a MAD.
+ */
+void
+mifare_application_free (Mad mad, MadAid aid)
+{
+ MifareSectorNumber *sectors = mifare_application_find (mad, aid);
+ MifareSectorNumber *p = sectors;
+ MadAid free_aid = { 0x00, 0x00 };
+ while (*p) {
+ mad_set_aid (mad, *p, free_aid);
+ p++;
+ }
+
+ free (sectors);
+}
+
+
+/*
+ * Application owner functions.
+ */
+
+/*
+ * Get all sector numbers of an application from the provided MAD.
+ */
+MifareSectorNumber *
+mifare_application_find (Mad mad, MadAid aid)
+{
+ MifareSectorNumber *res = NULL;
+ size_t res_count = count_aids (mad, aid);
+
+ if (res_count)
+ res = malloc (sizeof (*res) * res_count + 1);
+
+ size_t r = FIRST_SECTOR, w = 0;
+ if (res) {
+ /* Fill in the result */
+ MadAid c_aid;
+ while (w < res_count) {
+ mad_get_aid (mad, r, &c_aid);
+ if (0 == aidcmp (c_aid, aid)) {
+ res[w++] = r;
+ }
+ r++;
+ }
+ res[w] = 0;
+ }
+
+ return res;
+}
+
diff --git a/mifare_application.h b/mifare_application.h
new file mode 100644
index 0000000..d7f34d6
--- /dev/null
+++ b/mifare_application.h
@@ -0,0 +1,12 @@
+#ifndef __MAD_DATA_H__
+#define __MAD_DATA_H__
+
+#include
+
+MifareSectorNumber *mifare_application_alloc (Mad mad, MadAid aid, size_t size);
+void mifare_application_free (Mad mad, MadAid aid);
+
+MifareSectorNumber *mifare_application_find (Mad mad, MadAid aid);
+
+
+#endif /* !__MAD_DATA_H__ */
diff --git a/test/Makefile b/test/Makefile
index 54705a7..15dadb8 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -2,7 +2,7 @@ LMF_SRCDIR= ${.CURDIR}/..
.PATH: ${LMF_SRCDIR}
#LMF_SRCS!= ${MAKE} -f ${LMF_SRCDIR}/Makefile -V SRCS
-LMF_SRCS= ../mifare_classic.c ../mad.c
+LMF_SRCS= ../mifare_classic.c ../mad.c ../mifare_application.c
TESTS= test_read_sector_0.c \
test_authenticate.c \
@@ -10,7 +10,8 @@ TESTS= test_read_sector_0.c \
test_access_bits.c \
test_format.c \
test_create_trailer_block.c \
- test_mad.c
+ test_mad.c \
+ test_mifare_application.c
SRCS= ${LMF_SRCS} \
${TESTS} \
diff --git a/test/test.h b/test/test.h
index e9ec5b0..c00f0aa 100644
--- a/test/test.h
+++ b/test/test.h
@@ -206,6 +206,7 @@ int read_open_memory2(struct archive *, void *, size_t, size_t);
#include
#include
#include
+#include
int mifare_classic_test_setup (MifareClassicTag *tag);
int mifare_classic_test_teardown (MifareClassicTag tag);
diff --git a/test/test_mifare_application.c b/test/test_mifare_application.c
new file mode 100644
index 0000000..5c58382
--- /dev/null
+++ b/test/test_mifare_application.c
@@ -0,0 +1,37 @@
+#include "test.h"
+
+DEFINE_TEST(test_mifare_application)
+{
+ do {
+
+ /* Card publisher part */
+
+ MadAid aid = { 0x22, 0x42 };
+ Mad mad = mad_new (2);
+ assert (NULL != mad);
+
+ MifareSectorNumber *s_alloc = mifare_application_alloc (mad, aid, 3);
+ assert (NULL != s_alloc);
+
+ MifareSectorNumber *s_found = mifare_application_find (mad, aid);
+ assert (NULL != s_found);
+
+ for (int i = 0; i < 3; i++) {
+ assertEqualInt (s_alloc[i], s_found[i]);
+ }
+
+ assertEqualInt (0, s_alloc[3]);
+ assertEqualInt (0, s_found[3]);
+
+ mifare_application_free (mad, aid);
+
+ free (s_alloc);
+ free (s_found);
+
+ s_found = mifare_application_find (mad, aid);
+ assert (s_found == NULL);
+
+ mad_free (mad);
+
+ } while (0);
+}