kernel32/tests: Add more partial DBCS character tests that contains a null character.
[wine.git] / dlls / dnsapi / record.c
blob7882b2290fce738d75a494919b455be8fefb94d9
1 /*
2 * DNS support
4 * Copyright (C) 2006 Hans Leidekker
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <sys/types.h>
30 #ifdef HAVE_NETINET_IN_H
31 # include <netinet/in.h>
32 #endif
33 #ifdef HAVE_ARPA_NAMESER_H
34 # include <arpa/nameser.h>
35 #endif
36 #ifdef HAVE_RESOLV_H
37 # include <resolv.h>
38 #endif
40 #include "windef.h"
41 #include "winbase.h"
42 #include "winnls.h"
43 #include "windns.h"
45 #include "dnsapi.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(dnsapi);
49 const char *dns_type_to_str( unsigned short type )
51 switch (type)
53 #define X(x) case (x): return #x;
54 X(DNS_TYPE_ZERO)
55 X(DNS_TYPE_A)
56 X(DNS_TYPE_NS)
57 X(DNS_TYPE_MD)
58 X(DNS_TYPE_MF)
59 X(DNS_TYPE_CNAME)
60 X(DNS_TYPE_SOA)
61 X(DNS_TYPE_MB)
62 X(DNS_TYPE_MG)
63 X(DNS_TYPE_MR)
64 X(DNS_TYPE_NULL)
65 X(DNS_TYPE_WKS)
66 X(DNS_TYPE_PTR)
67 X(DNS_TYPE_HINFO)
68 X(DNS_TYPE_MINFO)
69 X(DNS_TYPE_MX)
70 X(DNS_TYPE_TEXT)
71 X(DNS_TYPE_RP)
72 X(DNS_TYPE_AFSDB)
73 X(DNS_TYPE_X25)
74 X(DNS_TYPE_ISDN)
75 X(DNS_TYPE_RT)
76 X(DNS_TYPE_NSAP)
77 X(DNS_TYPE_NSAPPTR)
78 X(DNS_TYPE_SIG)
79 X(DNS_TYPE_KEY)
80 X(DNS_TYPE_PX)
81 X(DNS_TYPE_GPOS)
82 X(DNS_TYPE_AAAA)
83 X(DNS_TYPE_LOC)
84 X(DNS_TYPE_NXT)
85 X(DNS_TYPE_EID)
86 X(DNS_TYPE_NIMLOC)
87 X(DNS_TYPE_SRV)
88 X(DNS_TYPE_ATMA)
89 X(DNS_TYPE_NAPTR)
90 X(DNS_TYPE_KX)
91 X(DNS_TYPE_CERT)
92 X(DNS_TYPE_A6)
93 X(DNS_TYPE_DNAME)
94 X(DNS_TYPE_SINK)
95 X(DNS_TYPE_OPT)
96 X(DNS_TYPE_UINFO)
97 X(DNS_TYPE_UID)
98 X(DNS_TYPE_GID)
99 X(DNS_TYPE_UNSPEC)
100 X(DNS_TYPE_ADDRS)
101 X(DNS_TYPE_TKEY)
102 X(DNS_TYPE_TSIG)
103 X(DNS_TYPE_IXFR)
104 X(DNS_TYPE_AXFR)
105 X(DNS_TYPE_MAILB)
106 X(DNS_TYPE_MAILA)
107 X(DNS_TYPE_ANY)
108 X(DNS_TYPE_WINS)
109 X(DNS_TYPE_WINSR)
110 #undef X
111 default: { static char tmp[7]; sprintf( tmp, "0x%04x", type ); return tmp; }
115 static int dns_strcmpX( LPCVOID str1, LPCVOID str2, BOOL wide )
117 if (wide)
118 return lstrcmpiW( str1, str2 );
119 else
120 return lstrcmpiA( str1, str2 );
123 /******************************************************************************
124 * DnsRecordCompare [DNSAPI.@]
127 BOOL WINAPI DnsRecordCompare( PDNS_RECORD r1, PDNS_RECORD r2 )
129 BOOL wide;
130 unsigned int i;
132 TRACE( "(%p,%p)\n", r1, r2 );
134 if (r1->wType != r2->wType ||
135 r1->wDataLength != r2->wDataLength ||
136 r1->Flags.S.Section != r2->Flags.S.Section ||
137 r1->Flags.S.Delete != r2->Flags.S.Delete ||
138 r1->Flags.S.Unused != r2->Flags.S.Unused ||
139 r1->Flags.S.Reserved != r2->Flags.S.Reserved ||
140 r1->dwReserved != r2->dwReserved) return FALSE;
142 wide = (r1->Flags.S.CharSet == DnsCharSetUnicode || r1->Flags.S.CharSet == DnsCharSetUnknown);
143 if (dns_strcmpX( r1->pName, r2->pName, wide )) return FALSE;
145 switch (r1->wType)
147 case DNS_TYPE_A:
149 if (r1->Data.A.IpAddress != r2->Data.A.IpAddress) return FALSE;
150 break;
152 case DNS_TYPE_SOA:
154 if (r1->Data.SOA.dwSerialNo != r2->Data.SOA.dwSerialNo ||
155 r1->Data.SOA.dwRefresh != r2->Data.SOA.dwRefresh ||
156 r1->Data.SOA.dwRetry != r2->Data.SOA.dwRetry ||
157 r1->Data.SOA.dwExpire != r2->Data.SOA.dwExpire ||
158 r1->Data.SOA.dwDefaultTtl != r2->Data.SOA.dwDefaultTtl)
159 return FALSE;
160 if (dns_strcmpX( r1->Data.SOA.pNamePrimaryServer,
161 r2->Data.SOA.pNamePrimaryServer, wide ) ||
162 dns_strcmpX( r1->Data.SOA.pNameAdministrator,
163 r2->Data.SOA.pNameAdministrator, wide ))
164 return FALSE;
165 break;
167 case DNS_TYPE_PTR:
168 case DNS_TYPE_NS:
169 case DNS_TYPE_CNAME:
170 case DNS_TYPE_MB:
171 case DNS_TYPE_MD:
172 case DNS_TYPE_MF:
173 case DNS_TYPE_MG:
174 case DNS_TYPE_MR:
176 if (dns_strcmpX( r1->Data.PTR.pNameHost,
177 r2->Data.PTR.pNameHost, wide )) return FALSE;
178 break;
180 case DNS_TYPE_MINFO:
181 case DNS_TYPE_RP:
183 if (dns_strcmpX( r1->Data.MINFO.pNameMailbox,
184 r2->Data.MINFO.pNameMailbox, wide ) ||
185 dns_strcmpX( r1->Data.MINFO.pNameErrorsMailbox,
186 r2->Data.MINFO.pNameErrorsMailbox, wide ))
187 return FALSE;
188 break;
190 case DNS_TYPE_MX:
191 case DNS_TYPE_AFSDB:
192 case DNS_TYPE_RT:
194 if (r1->Data.MX.wPreference != r2->Data.MX.wPreference)
195 return FALSE;
196 if (dns_strcmpX( r1->Data.MX.pNameExchange,
197 r2->Data.MX.pNameExchange, wide ))
198 return FALSE;
199 break;
201 case DNS_TYPE_HINFO:
202 case DNS_TYPE_ISDN:
203 case DNS_TYPE_TEXT:
204 case DNS_TYPE_X25:
206 if (r1->Data.TXT.dwStringCount != r2->Data.TXT.dwStringCount)
207 return FALSE;
208 for (i = 0; i < r1->Data.TXT.dwStringCount; i++)
210 if (dns_strcmpX( r1->Data.TXT.pStringArray[i],
211 r2->Data.TXT.pStringArray[i], wide ))
212 return FALSE;
214 break;
216 case DNS_TYPE_NULL:
218 if (r1->Data.Null.dwByteCount != r2->Data.Null.dwByteCount)
219 return FALSE;
220 if (memcmp( r1->Data.Null.Data,
221 r2->Data.Null.Data, r1->Data.Null.dwByteCount ))
222 return FALSE;
223 break;
225 case DNS_TYPE_AAAA:
227 for (i = 0; i < sizeof(IP6_ADDRESS)/sizeof(DWORD); i++)
229 if (r1->Data.AAAA.Ip6Address.IP6Dword[i] !=
230 r2->Data.AAAA.Ip6Address.IP6Dword[i]) return FALSE;
232 break;
234 case DNS_TYPE_KEY:
236 if (r1->Data.KEY.wFlags != r2->Data.KEY.wFlags ||
237 r1->Data.KEY.chProtocol != r2->Data.KEY.chProtocol ||
238 r1->Data.KEY.chAlgorithm != r2->Data.KEY.chAlgorithm)
239 return FALSE;
240 if (memcmp( r1->Data.KEY.Key, r2->Data.KEY.Key,
241 r1->wDataLength - sizeof(DNS_KEY_DATA) + 1 ))
242 return FALSE;
243 break;
245 case DNS_TYPE_SIG:
247 if (dns_strcmpX( r1->Data.SIG.pNameSigner,
248 r2->Data.SIG.pNameSigner, wide ))
249 return FALSE;
250 if (r1->Data.SIG.wTypeCovered != r2->Data.SIG.wTypeCovered ||
251 r1->Data.SIG.chAlgorithm != r2->Data.SIG.chAlgorithm ||
252 r1->Data.SIG.chLabelCount != r2->Data.SIG.chLabelCount ||
253 r1->Data.SIG.dwOriginalTtl != r2->Data.SIG.dwOriginalTtl ||
254 r1->Data.SIG.dwExpiration != r2->Data.SIG.dwExpiration ||
255 r1->Data.SIG.dwTimeSigned != r2->Data.SIG.dwTimeSigned ||
256 r1->Data.SIG.wKeyTag != r2->Data.SIG.wKeyTag)
257 return FALSE;
258 if (memcmp( r1->Data.SIG.Signature, r2->Data.SIG.Signature,
259 r1->wDataLength - sizeof(DNS_SIG_DATAA) + 1 ))
260 return FALSE;
261 break;
263 case DNS_TYPE_ATMA:
265 if (r1->Data.ATMA.AddressType != r2->Data.ATMA.AddressType)
266 return FALSE;
267 for (i = 0; i < DNS_ATMA_MAX_ADDR_LENGTH; i++)
269 if (r1->Data.ATMA.Address[i] != r2->Data.ATMA.Address[i])
270 return FALSE;
272 break;
274 case DNS_TYPE_NXT:
276 if (dns_strcmpX( r1->Data.NXT.pNameNext,
277 r2->Data.NXT.pNameNext, wide )) return FALSE;
278 if (r1->Data.NXT.wNumTypes != r2->Data.NXT.wNumTypes) return FALSE;
279 if (memcmp( r1->Data.NXT.wTypes, r2->Data.NXT.wTypes,
280 r1->wDataLength - sizeof(DNS_NXT_DATAA) + sizeof(WORD) ))
281 return FALSE;
282 break;
284 case DNS_TYPE_SRV:
286 if (dns_strcmpX( r1->Data.SRV.pNameTarget,
287 r2->Data.SRV.pNameTarget, wide )) return FALSE;
288 if (r1->Data.SRV.wPriority != r2->Data.SRV.wPriority ||
289 r1->Data.SRV.wWeight != r2->Data.SRV.wWeight ||
290 r1->Data.SRV.wPort != r2->Data.SRV.wPort)
291 return FALSE;
292 break;
294 case DNS_TYPE_TKEY:
296 if (dns_strcmpX( r1->Data.TKEY.pNameAlgorithm,
297 r2->Data.TKEY.pNameAlgorithm, wide ))
298 return FALSE;
299 if (r1->Data.TKEY.dwCreateTime != r2->Data.TKEY.dwCreateTime ||
300 r1->Data.TKEY.dwExpireTime != r2->Data.TKEY.dwExpireTime ||
301 r1->Data.TKEY.wMode != r2->Data.TKEY.wMode ||
302 r1->Data.TKEY.wError != r2->Data.TKEY.wError ||
303 r1->Data.TKEY.wKeyLength != r2->Data.TKEY.wKeyLength ||
304 r1->Data.TKEY.wOtherLength != r2->Data.TKEY.wOtherLength ||
305 r1->Data.TKEY.cAlgNameLength != r2->Data.TKEY.cAlgNameLength ||
306 r1->Data.TKEY.bPacketPointers != r2->Data.TKEY.bPacketPointers)
307 return FALSE;
309 /* FIXME: ignoring pAlgorithmPacket field */
310 if (memcmp( r1->Data.TKEY.pKey, r2->Data.TKEY.pKey,
311 r1->Data.TKEY.wKeyLength ) ||
312 memcmp( r1->Data.TKEY.pOtherData, r2->Data.TKEY.pOtherData,
313 r1->Data.TKEY.wOtherLength )) return FALSE;
314 break;
316 case DNS_TYPE_TSIG:
318 if (dns_strcmpX( r1->Data.TSIG.pNameAlgorithm,
319 r2->Data.TSIG.pNameAlgorithm, wide ))
320 return FALSE;
321 if (r1->Data.TSIG.i64CreateTime != r2->Data.TSIG.i64CreateTime ||
322 r1->Data.TSIG.wFudgeTime != r2->Data.TSIG.wFudgeTime ||
323 r1->Data.TSIG.wOriginalXid != r2->Data.TSIG.wOriginalXid ||
324 r1->Data.TSIG.wError != r2->Data.TSIG.wError ||
325 r1->Data.TSIG.wSigLength != r2->Data.TSIG.wSigLength ||
326 r1->Data.TSIG.wOtherLength != r2->Data.TSIG.wOtherLength ||
327 r1->Data.TSIG.cAlgNameLength != r2->Data.TSIG.cAlgNameLength ||
328 r1->Data.TSIG.bPacketPointers != r2->Data.TSIG.bPacketPointers)
329 return FALSE;
331 /* FIXME: ignoring pAlgorithmPacket field */
332 if (memcmp( r1->Data.TSIG.pSignature, r2->Data.TSIG.pSignature,
333 r1->Data.TSIG.wSigLength ) ||
334 memcmp( r1->Data.TSIG.pOtherData, r2->Data.TSIG.pOtherData,
335 r1->Data.TSIG.wOtherLength )) return FALSE;
336 break;
338 case DNS_TYPE_WINS:
340 if (r1->Data.WINS.dwMappingFlag != r2->Data.WINS.dwMappingFlag ||
341 r1->Data.WINS.dwLookupTimeout != r2->Data.WINS.dwLookupTimeout ||
342 r1->Data.WINS.dwCacheTimeout != r2->Data.WINS.dwCacheTimeout ||
343 r1->Data.WINS.cWinsServerCount != r2->Data.WINS.cWinsServerCount)
344 return FALSE;
345 if (memcmp( r1->Data.WINS.WinsServers, r2->Data.WINS.WinsServers,
346 r1->wDataLength - sizeof(DNS_WINS_DATA) + sizeof(IP4_ADDRESS) ))
347 return FALSE;
348 break;
350 case DNS_TYPE_WINSR:
352 if (r1->Data.WINSR.dwMappingFlag != r2->Data.WINSR.dwMappingFlag ||
353 r1->Data.WINSR.dwLookupTimeout != r2->Data.WINSR.dwLookupTimeout ||
354 r1->Data.WINSR.dwCacheTimeout != r2->Data.WINSR.dwCacheTimeout)
355 return FALSE;
356 if (dns_strcmpX( r1->Data.WINSR.pNameResultDomain,
357 r2->Data.WINSR.pNameResultDomain, wide ))
358 return FALSE;
359 break;
361 default:
362 FIXME( "unknown type: %s\n", dns_type_to_str( r1->wType ) );
363 return FALSE;
365 return TRUE;
368 static LPVOID dns_strcpyX( LPCVOID src, DNS_CHARSET in, DNS_CHARSET out )
370 switch (in)
372 case DnsCharSetUnicode:
374 switch (out)
376 case DnsCharSetUnicode: return dns_strdup_w( src );
377 case DnsCharSetUtf8: return dns_strdup_wu( src );
378 case DnsCharSetAnsi: return dns_strdup_wa( src );
379 default:
380 WARN( "unhandled target charset: %d\n", out );
381 break;
383 break;
385 case DnsCharSetUtf8:
386 switch (out)
388 case DnsCharSetUnicode: return dns_strdup_uw( src );
389 case DnsCharSetUtf8: return dns_strdup_u( src );
390 case DnsCharSetAnsi: return dns_strdup_ua( src );
391 default:
392 WARN( "unhandled target charset: %d\n", out );
393 break;
395 break;
396 case DnsCharSetAnsi:
397 switch (out)
399 case DnsCharSetUnicode: return dns_strdup_aw( src );
400 case DnsCharSetUtf8: return dns_strdup_au( src );
401 case DnsCharSetAnsi: return dns_strdup_a( src );
402 default:
403 WARN( "unhandled target charset: %d\n", out );
404 break;
406 break;
407 default:
408 WARN( "unhandled source charset: %d\n", in );
409 break;
411 return NULL;
414 /******************************************************************************
415 * DnsRecordCopyEx [DNSAPI.@]
418 PDNS_RECORD WINAPI DnsRecordCopyEx( PDNS_RECORD src, DNS_CHARSET in, DNS_CHARSET out )
420 DNS_RECORD *dst;
421 unsigned int i, size;
423 TRACE( "(%p,%d,%d)\n", src, in, out );
425 size = FIELD_OFFSET(DNS_RECORD, Data) + src->wDataLength;
426 dst = heap_alloc_zero( size );
427 if (!dst) return NULL;
429 memcpy( dst, src, size );
431 if (src->Flags.S.CharSet == DnsCharSetUtf8 ||
432 src->Flags.S.CharSet == DnsCharSetAnsi ||
433 src->Flags.S.CharSet == DnsCharSetUnicode) in = src->Flags.S.CharSet;
435 dst->Flags.S.CharSet = out;
436 dst->pName = dns_strcpyX( src->pName, in, out );
437 if (!dst->pName) goto error;
439 switch (src->wType)
441 case DNS_TYPE_HINFO:
442 case DNS_TYPE_ISDN:
443 case DNS_TYPE_TEXT:
444 case DNS_TYPE_X25:
446 for (i = 0; i < src->Data.TXT.dwStringCount; i++)
448 dst->Data.TXT.pStringArray[i] =
449 dns_strcpyX( src->Data.TXT.pStringArray[i], in, out );
451 if (!dst->Data.TXT.pStringArray[i])
453 while (i > 0) heap_free( dst->Data.TXT.pStringArray[--i] );
454 goto error;
457 break;
459 case DNS_TYPE_MINFO:
460 case DNS_TYPE_RP:
462 dst->Data.MINFO.pNameMailbox =
463 dns_strcpyX( src->Data.MINFO.pNameMailbox, in, out );
464 if (!dst->Data.MINFO.pNameMailbox) goto error;
466 dst->Data.MINFO.pNameErrorsMailbox =
467 dns_strcpyX( src->Data.MINFO.pNameErrorsMailbox, in, out );
468 if (!dst->Data.MINFO.pNameErrorsMailbox)
470 heap_free( dst->Data.MINFO.pNameMailbox );
471 goto error;
473 break;
475 case DNS_TYPE_AFSDB:
476 case DNS_TYPE_RT:
477 case DNS_TYPE_MX:
479 dst->Data.MX.pNameExchange =
480 dns_strcpyX( src->Data.MX.pNameExchange, in, out );
481 if (!dst->Data.MX.pNameExchange) goto error;
482 break;
484 case DNS_TYPE_NXT:
486 dst->Data.NXT.pNameNext =
487 dns_strcpyX( src->Data.NXT.pNameNext, in, out );
488 if (!dst->Data.NXT.pNameNext) goto error;
489 break;
491 case DNS_TYPE_CNAME:
492 case DNS_TYPE_MB:
493 case DNS_TYPE_MD:
494 case DNS_TYPE_MF:
495 case DNS_TYPE_MG:
496 case DNS_TYPE_MR:
497 case DNS_TYPE_NS:
498 case DNS_TYPE_PTR:
500 dst->Data.PTR.pNameHost =
501 dns_strcpyX( src->Data.PTR.pNameHost, in, out );
502 if (!dst->Data.PTR.pNameHost) goto error;
503 break;
505 case DNS_TYPE_SIG:
507 dst->Data.SIG.pNameSigner =
508 dns_strcpyX( src->Data.SIG.pNameSigner, in, out );
509 if (!dst->Data.SIG.pNameSigner) goto error;
510 break;
512 case DNS_TYPE_SOA:
514 dst->Data.SOA.pNamePrimaryServer =
515 dns_strcpyX( src->Data.SOA.pNamePrimaryServer, in, out );
516 if (!dst->Data.SOA.pNamePrimaryServer) goto error;
518 dst->Data.SOA.pNameAdministrator =
519 dns_strcpyX( src->Data.SOA.pNameAdministrator, in, out );
520 if (!dst->Data.SOA.pNameAdministrator)
522 heap_free( dst->Data.SOA.pNamePrimaryServer );
523 goto error;
525 break;
527 case DNS_TYPE_SRV:
529 dst->Data.SRV.pNameTarget =
530 dns_strcpyX( src->Data.SRV.pNameTarget, in, out );
531 if (!dst->Data.SRV.pNameTarget) goto error;
532 break;
534 default:
535 break;
537 return dst;
539 error:
540 heap_free( dst->pName );
541 heap_free( dst );
542 return NULL;
545 /******************************************************************************
546 * DnsRecordListFree [DNSAPI.@]
549 VOID WINAPI DnsRecordListFree( PDNS_RECORD list, DNS_FREE_TYPE type )
551 DNS_RECORD *r, *next;
552 unsigned int i;
554 TRACE( "(%p,%d)\n", list, type );
556 if (!list) return;
558 switch (type)
560 case DnsFreeRecordList:
562 for (r = list; (list = r); r = next)
564 heap_free( r->pName );
566 switch (r->wType)
568 case DNS_TYPE_HINFO:
569 case DNS_TYPE_ISDN:
570 case DNS_TYPE_TEXT:
571 case DNS_TYPE_X25:
573 for (i = 0; i < r->Data.TXT.dwStringCount; i++)
574 heap_free( r->Data.TXT.pStringArray[i] );
576 break;
578 case DNS_TYPE_MINFO:
579 case DNS_TYPE_RP:
581 heap_free( r->Data.MINFO.pNameMailbox );
582 heap_free( r->Data.MINFO.pNameErrorsMailbox );
583 break;
585 case DNS_TYPE_AFSDB:
586 case DNS_TYPE_RT:
587 case DNS_TYPE_MX:
589 heap_free( r->Data.MX.pNameExchange );
590 break;
592 case DNS_TYPE_NXT:
594 heap_free( r->Data.NXT.pNameNext );
595 break;
597 case DNS_TYPE_CNAME:
598 case DNS_TYPE_MB:
599 case DNS_TYPE_MD:
600 case DNS_TYPE_MF:
601 case DNS_TYPE_MG:
602 case DNS_TYPE_MR:
603 case DNS_TYPE_NS:
604 case DNS_TYPE_PTR:
606 heap_free( r->Data.PTR.pNameHost );
607 break;
609 case DNS_TYPE_SIG:
611 heap_free( r->Data.SIG.pNameSigner );
612 break;
614 case DNS_TYPE_SOA:
616 heap_free( r->Data.SOA.pNamePrimaryServer );
617 heap_free( r->Data.SOA.pNameAdministrator );
618 break;
620 case DNS_TYPE_SRV:
622 heap_free( r->Data.SRV.pNameTarget );
623 break;
625 default:
626 break;
629 next = r->pNext;
630 heap_free( r );
632 break;
634 case DnsFreeFlat:
635 case DnsFreeParsedMessageFields:
637 FIXME( "unhandled free type: %d\n", type );
638 break;
640 default:
641 WARN( "unknown free type: %d\n", type );
642 break;
646 /******************************************************************************
647 * DnsFree [DNSAPI.@]
650 void WINAPI DnsFree( PVOID data, DNS_FREE_TYPE type )
652 DnsRecordListFree( data, type );
655 /******************************************************************************
656 * DnsRecordSetCompare [DNSAPI.@]
659 BOOL WINAPI DnsRecordSetCompare( PDNS_RECORD set1, PDNS_RECORD set2,
660 PDNS_RECORD *diff1, PDNS_RECORD *diff2 )
662 BOOL ret = TRUE;
663 DNS_RECORD *r, *t, *u;
664 DNS_RRSET rr1, rr2;
666 TRACE( "(%p,%p,%p,%p)\n", set1, set2, diff1, diff2 );
668 if (!set1 && !set2) return FALSE;
670 if (diff1) *diff1 = NULL;
671 if (diff2) *diff2 = NULL;
673 if (set1 && !set2)
675 if (diff1) *diff1 = DnsRecordSetCopyEx( set1, 0, set1->Flags.S.CharSet );
676 return FALSE;
678 if (!set1 && set2)
680 if (diff2) *diff2 = DnsRecordSetCopyEx( set2, 0, set2->Flags.S.CharSet );
681 return FALSE;
684 DNS_RRSET_INIT( rr1 );
685 DNS_RRSET_INIT( rr2 );
687 for (r = set1; r; r = r->pNext)
689 for (t = set2; t; t = t->pNext)
691 u = DnsRecordCopyEx( r, r->Flags.S.CharSet, t->Flags.S.CharSet );
692 if (!u) goto error;
694 if (!DnsRecordCompare( t, u ))
696 DNS_RRSET_ADD( rr1, u );
697 ret = FALSE;
699 else DnsRecordListFree( u, DnsFreeRecordList );
703 for (t = set2; t; t = t->pNext)
705 for (r = set1; r; r = r->pNext)
707 u = DnsRecordCopyEx( t, t->Flags.S.CharSet, r->Flags.S.CharSet );
708 if (!u) goto error;
710 if (!DnsRecordCompare( r, u ))
712 DNS_RRSET_ADD( rr2, u );
713 ret = FALSE;
715 else DnsRecordListFree( u, DnsFreeRecordList );
719 DNS_RRSET_TERMINATE( rr1 );
720 DNS_RRSET_TERMINATE( rr2 );
722 if (diff1) *diff1 = rr1.pFirstRR;
723 else DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
725 if (diff2) *diff2 = rr2.pFirstRR;
726 else DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
728 return ret;
730 error:
731 DNS_RRSET_TERMINATE( rr1 );
732 DNS_RRSET_TERMINATE( rr2 );
734 DnsRecordListFree( rr1.pFirstRR, DnsFreeRecordList );
735 DnsRecordListFree( rr2.pFirstRR, DnsFreeRecordList );
737 return FALSE;
740 /******************************************************************************
741 * DnsRecordSetCopyEx [DNSAPI.@]
744 PDNS_RECORD WINAPI DnsRecordSetCopyEx( PDNS_RECORD src_set, DNS_CHARSET in, DNS_CHARSET out )
746 DNS_RRSET dst_set;
747 DNS_RECORD *src, *dst;
749 TRACE( "(%p,%d,%d)\n", src_set, in, out );
751 DNS_RRSET_INIT( dst_set );
753 for (src = src_set; (src_set = src); src = src_set->pNext)
755 dst = DnsRecordCopyEx( src, in, out );
756 if (!dst)
758 DNS_RRSET_TERMINATE( dst_set );
759 DnsRecordListFree( dst_set.pFirstRR, DnsFreeRecordList );
760 return NULL;
762 DNS_RRSET_ADD( dst_set, dst );
765 DNS_RRSET_TERMINATE( dst_set );
766 return dst_set.pFirstRR;
769 /******************************************************************************
770 * DnsRecordSetDetach [DNSAPI.@]
773 PDNS_RECORD WINAPI DnsRecordSetDetach( PDNS_RECORD set )
775 DNS_RECORD *r, *s;
777 TRACE( "(%p)\n", set );
779 for (r = set; (set = r); r = set->pNext)
781 if (r->pNext && !r->pNext->pNext)
783 s = r->pNext;
784 r->pNext = NULL;
785 return s;
788 return NULL;