/*
         * Read byte[] as a string array. At most 9 octets reveal the size of the array (string element count).
         */
        public static DeserializationFieldResult readStringArray(byte[] data, int idx)
        {
            DeserializationFieldResult res = new DeserializationFieldResult {
            };
            CMap <int, string> map         = new CMap <int, string> {
            };

            map.map = new Map <int, string>();

            VarSizeStr countStr = readVarSize(data, idx);

            res.size = countStr.size;
            if (countStr.value == 0)
            {
                map.size    = 0;
                res.value   = map;
                res.isEmpty = true;
                return(res);
            }

            idx     += countStr.size;
            map.size = (int)countStr.value;
            for (int i = 0; i < map.size; ++i)
            {
                DeserializationFieldResult tempStr = readString(data, idx);

                map.map[i] = (string)tempStr.value;
                res.size   = res.size + tempStr.size;
                idx       += tempStr.size;
            }

            res.value   = map;
            res.isEmpty = false;
            return(res);
        }
        public static DeserializationFieldResult deserializeName(byte[] data, int idx)
        {
            int     initial = idx;
            NameStr name    = new NameStr();

            DeserializationFieldResult commonName = readByteArray(data, idx);

            name.CommonName = (byte[])commonName.value;
            idx            += commonName.size;

            DeserializationFieldResult country = readStringArray(data, idx);

            name.Country = (CMap <int, string>)country.value;
            idx         += country.size;

            DeserializationFieldResult organization = readStringArray(data, idx);

            name.Organization = (CMap <int, string>)organization.value;
            idx += organization.size;

            DeserializationFieldResult organizationalUnit = readStringArray(data, idx);

            name.OrganizationalUnit = (CMap <int, string>)organizationalUnit.value;
            idx += organizationalUnit.size;

            DeserializationFieldResult locality = readStringArray(data, idx);

            name.Locality = (CMap <int, string>)locality.value;
            idx          += locality.size;

            DeserializationFieldResult province = readStringArray(data, idx);

            name.Province = (CMap <int, string>)province.value;
            idx          += province.size;

            DeserializationFieldResult streetAddress = readStringArray(data, idx);

            name.StreetAddress = (CMap <int, string>)streetAddress.value;
            idx += streetAddress.size;

            DeserializationFieldResult postalCode = readStringArray(data, idx);

            name.PostalCode = (CMap <int, string>)postalCode.value;
            idx            += postalCode.size;

            DeserializationFieldResult serialNumber = readString(data, idx);

            name.SerialNumber = (string)serialNumber.value;
            idx += serialNumber.size;

            DeserializationFieldResult res = new DeserializationFieldResult {
            };

            res.value = name;
            res.size  = idx - initial;
            return(res);
        }
        /*
         * Read byte[] as a string. At most 9 octets are data size. See readByteArray()
         */
        public static DeserializationFieldResult readString(byte[] data, int idx)
        {
            DeserializationFieldResult res = readByteArray(data, idx);

            if (res.isEmpty)
            {
                return(res);
            }

            //else
            res.value = Helper.AsString((byte[])res.value);

            return(res);
        }
        /*
         * Read byte[] from the stream. At most 9 octets reveal the size of the array.
         */
        public static DeserializationFieldResult readByteArray(byte[] data, int idx)
        {
            DeserializationFieldResult res = new DeserializationFieldResult();

            res.size  = 0;
            res.value = null;

            VarSizeStr varSizeStr = readVarSize(data, idx);

            if (varSizeStr.value == 0)
            {
                res.isEmpty = true;
                res.size    = 1;
                return(res);
            }

            res.size  = varSizeStr.size + varSizeStr.value;
            res.value = Helper.Range(data, idx + varSizeStr.size, varSizeStr.value);

            return(res);
        }
        public static CertificateStr deserializeCertData(byte[] raw)
        {
            int            length = raw.Length;
            int            idx    = 0;
            CertificateStr cert   = new CertificateStr();

            cert.Version = readInt(raw, idx);
            idx         += 4;

            DeserializationFieldResult serialNumber = readByteArray(raw, idx);

            cert.SerialNumber = (byte[])serialNumber.value;
            idx += serialNumber.size;

            DeserializationFieldResult issuer = deserializeName(raw, idx);

            cert.issuer = (NameStr)issuer.value;
            idx        += issuer.size;

            DeserializationFieldResult subject = deserializeName(raw, idx);

            cert.subject = (NameStr)subject.value;
            idx         += subject.size;

            Validity validity = new Validity();

            validity.NotBefore = readLong(raw, idx); //check
            idx += 8;

            validity.NotAfter = readLong(raw, idx); //check
            idx          += 8;
            cert.Validity = validity;

            NativeExtendedKeyUsage extendedKeyUsage = new NativeExtendedKeyUsage();

            extendedKeyUsage.Count = readInt(raw, idx);
            idx += 4;

            DeserializationFieldResult extendedKeyUsageOIDs = readStringArray(raw, idx);

            extendedKeyUsage.Oids = (CMap <int, string>)extendedKeyUsageOIDs.value;
            idx += extendedKeyUsageOIDs.size;
            cert.ExtendedKeyUsage = extendedKeyUsage;

            NativeKeyUsage keyUsage = new NativeKeyUsage();

            keyUsage.Value = readInt(raw, idx);
            idx           += 4;
            cert.KeyUsage  = keyUsage;

            BasicConstraints basicConstraints = new BasicConstraints();

            basicConstraints.HasBasicConstraints = readBool(raw, idx);
            idx += 1;

            basicConstraints.IsCa = readBool(raw, idx);
            idx += 1;

            basicConstraints.MaxPathLen = readInt(raw, idx); //check FF FF FF FF becomes FF FF FE FE
            idx += 4;
            cert.BasicConstraints = basicConstraints;

            AuthorityKeyIdentifier     authorityKeyIdentifier = new AuthorityKeyIdentifier();
            DeserializationFieldResult authorityKeyId         = readByteArray(raw, idx);

            authorityKeyIdentifier.keyIdentifier = (byte[])authorityKeyId.value;
            if (authorityKeyId.size > 2)
            {
                authorityKeyIdentifier.HasAuthorityKeyIdentifier = true;
            }

            idx += authorityKeyId.size;
            cert.AuthorityKeyIdentifier = authorityKeyIdentifier;

            SubjectKeyIdentifier       subjectKeyIdentifier = new SubjectKeyIdentifier();
            DeserializationFieldResult subjectKeyId         = readByteArray(raw, idx);

            subjectKeyIdentifier.keyIdentifier = (byte[])subjectKeyId.value;
            if (subjectKeyId.size > 2)
            {
                subjectKeyIdentifier.HasSubjectKeyIdentifierExtension = true;
            }

            idx += subjectKeyId.size;
            cert.SubjectKeyIdentifier = subjectKeyIdentifier;

            DeserializationFieldResult dnsNames = readStringArray(raw, idx);

            cert.DnsNames = (CMap <int, string>)dnsNames.value;
            idx          += dnsNames.size;

            DeserializationFieldResult emailAddresses = readStringArray(raw, idx);

            cert.EmailAddresses = (CMap <int, string>)emailAddresses.value;
            idx += emailAddresses.size;

            DeserializationFieldResult ipAddresses = readStringArray(raw, idx);

            cert.IpAddresses = (CMap <int, string>)ipAddresses.value;
            idx += ipAddresses.size;

            DeserializationFieldResult urls = readStringArray(raw, idx);

            cert.Urls = (CMap <int, string>)urls.value;
            idx      += urls.size;

            DeserializationFieldResult tbsCertificate = readByteArray(raw, idx);

            cert.TbsCertificate = (byte[])tbsCertificate.value;
            idx += tbsCertificate.size;

            DeserializationFieldResult signatureAlgorithm = readByteArray(raw, idx);

            cert.SignatureAlgorithm = (byte[])signatureAlgorithm.value;
            idx += signatureAlgorithm.size;

            DeserializationFieldResult signatureValue = readByteArray(raw, idx);

            cert.Signature = (byte[])signatureValue.value;
            idx           += signatureValue.size;

            DeserializationFieldResult subjectPublicKeyInfo = readByteArray(raw, idx);

            cert.SubjectPublicKeyInfo = (byte[])subjectPublicKeyInfo.value;
            idx += subjectPublicKeyInfo.size;

            DeserializationFieldResult publicKeySignatureAlgorithm = readByteArray(raw, idx);

            cert.PublicKeyAlgName = (byte[])publicKeySignatureAlgorithm.value;
            idx += publicKeySignatureAlgorithm.size;

            DeserializationFieldResult tbsCertificateSignatureAlgorithm = readByteArray(raw, idx);

            cert.TBSSignatureAlgorithm = (byte[])tbsCertificateSignatureAlgorithm.value;
            idx += tbsCertificateSignatureAlgorithm.size;

            // todo return byte[] ?
            return(cert);
        }