]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 A |
1 | /* |
2 | * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved. | |
3 | * | |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please obtain | |
7 | * a copy of the License at http://www.apple.com/publicsource and read it before | |
8 | * using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS | |
12 | * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT | |
13 | * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
14 | * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the | |
15 | * specific language governing rights and limitations under the License. | |
16 | */ | |
17 | ||
18 | ||
19 | // | |
20 | // MetaRecord.cpp | |
21 | // | |
22 | ||
23 | #include "MetaRecord.h" | |
24 | #include <security_utilities/trackingallocator.h> | |
25 | #include <security_cdsa_utilities/cssmbridge.h> | |
26 | ||
27 | ||
28 | MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRecordType) : | |
29 | mRecordType(inRecordType) | |
30 | { | |
31 | } | |
32 | ||
33 | MetaRecord::MetaRecord(const CSSM_DB_RECORD_ATTRIBUTE_INFO &inInfo) | |
34 | : mRecordType(inInfo.DataRecordType) | |
35 | { | |
36 | try | |
37 | { | |
38 | setRecordAttributeInfo(inInfo); | |
39 | } | |
40 | catch (...) | |
41 | { | |
42 | for_each_delete(mAttributeVector.begin(), mAttributeVector.end()); | |
43 | } | |
44 | } | |
45 | ||
46 | MetaRecord::MetaRecord(CSSM_DB_RECORDTYPE inRelationID, | |
47 | uint32 inNumberOfAttributes, | |
48 | const CSSM_DB_SCHEMA_ATTRIBUTE_INFO *inAttributeInfo) : | |
49 | mRecordType(inRelationID) | |
50 | { | |
51 | try { | |
52 | for (uint32 anIndex = 0; anIndex < inNumberOfAttributes; anIndex++) | |
53 | { | |
54 | string aName; | |
55 | if (inAttributeInfo[anIndex].AttributeName) | |
56 | aName = string(inAttributeInfo[anIndex].AttributeName); | |
57 | ||
58 | const CssmData *aNameID = NULL; | |
59 | if (inAttributeInfo[anIndex].AttributeNameID.Length > 0) | |
60 | aNameID = &CssmData::overlay(inAttributeInfo[anIndex].AttributeNameID); | |
61 | ||
62 | uint32 aNumber = inAttributeInfo[anIndex].AttributeId; | |
63 | createAttribute( | |
64 | inAttributeInfo[anIndex].AttributeName ? &aName : NULL, | |
65 | aNameID, aNumber, | |
66 | inAttributeInfo[anIndex].DataType); | |
67 | } | |
68 | } | |
69 | catch (...) | |
70 | { | |
71 | for_each_delete(mAttributeVector.begin(), mAttributeVector.end()); | |
72 | } | |
73 | } | |
74 | ||
75 | MetaRecord::~MetaRecord() | |
76 | { | |
77 | // for_each_delete(mAttributeVector.begin(), mAttributeVector.end()); | |
78 | AttributeVector::iterator it = mAttributeVector.begin(); | |
79 | while (it != mAttributeVector.end()) | |
80 | { | |
81 | MetaAttribute* mat = *it++; | |
82 | if (mat != NULL) | |
83 | { | |
84 | delete mat; | |
85 | } | |
86 | } | |
87 | } | |
88 | ||
89 | void | |
90 | MetaRecord::setRecordAttributeInfo(const CSSM_DB_RECORD_ATTRIBUTE_INFO &inInfo) | |
91 | { | |
92 | for (uint32 anIndex = 0; anIndex < inInfo.NumberOfAttributes; anIndex++) | |
93 | { | |
94 | switch (inInfo.AttributeInfo[anIndex].AttributeNameFormat) | |
95 | { | |
96 | case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: | |
97 | { | |
98 | string aName(inInfo.AttributeInfo[anIndex].Label.AttributeName); | |
99 | createAttribute(&aName, nil, anIndex, | |
100 | inInfo.AttributeInfo[anIndex].AttributeFormat); | |
101 | break; | |
102 | } | |
103 | case CSSM_DB_ATTRIBUTE_NAME_AS_OID: | |
104 | { | |
105 | const CssmData &aNameID = CssmOid::overlay(inInfo.AttributeInfo[anIndex].Label.AttributeOID); | |
106 | createAttribute(nil, &aNameID, anIndex, | |
107 | inInfo.AttributeInfo[anIndex].AttributeFormat); | |
108 | break; | |
109 | } | |
110 | case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: | |
111 | { | |
112 | uint32 aNumber = inInfo.AttributeInfo[anIndex].Label.AttributeID; | |
113 | createAttribute(nil, nil, aNumber, | |
114 | inInfo.AttributeInfo[anIndex].AttributeFormat); | |
115 | break; | |
116 | } | |
117 | default: | |
118 | CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); | |
119 | break; | |
120 | } | |
121 | } | |
122 | } | |
123 | ||
124 | void | |
125 | MetaRecord::createAttribute(const string *inAttributeName, | |
126 | const CssmOid *inAttributeOID, | |
127 | uint32 inAttributeID, | |
128 | CSSM_DB_ATTRIBUTE_FORMAT inAttributeFormat) | |
129 | { | |
130 | // Index of new element is current size of vector | |
427c49bc | 131 | uint32 anAttributeIndex = (uint32)mAttributeVector.size(); |
b1ab9ed8 A |
132 | bool aInsertedAttributeName = false; |
133 | bool aInsertedAttributeOID = false; | |
134 | bool aInsertedAttributeID = false; | |
135 | ||
136 | if (inAttributeName) | |
137 | { | |
138 | if (!mNameStringMap.insert(NameStringMap::value_type(*inAttributeName, anAttributeIndex)).second) | |
139 | CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE); | |
140 | aInsertedAttributeName = true; | |
141 | } | |
142 | try | |
143 | { | |
144 | if (inAttributeOID) | |
145 | { | |
146 | if (!mNameOIDMap.insert(NameOIDMap::value_type(*inAttributeOID, anAttributeIndex)).second) | |
147 | CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE); | |
148 | aInsertedAttributeOID = true; | |
149 | } | |
150 | ||
151 | if (!mNameIntMap.insert(NameIntMap::value_type(inAttributeID, anAttributeIndex)).second) | |
152 | CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE); | |
153 | aInsertedAttributeID = true; | |
154 | ||
155 | // Note: this no longer throws INVALID_FIELD_NAME since the attribute will always have | |
156 | // an attribute ID by which it is known | |
157 | ||
158 | mAttributeVector.push_back(MetaAttribute::create(inAttributeFormat, | |
159 | anAttributeIndex, inAttributeID)); | |
160 | } | |
161 | catch(...) | |
162 | { | |
163 | if (aInsertedAttributeName) | |
164 | mNameStringMap.erase(*inAttributeName); | |
165 | if (aInsertedAttributeOID) | |
166 | mNameOIDMap.erase(*inAttributeOID); | |
167 | if (inAttributeID) | |
168 | mNameIntMap.erase(inAttributeID); | |
169 | ||
170 | throw; | |
171 | } | |
172 | } | |
173 | ||
174 | ||
175 | // Create a packed record from the given inputs. | |
176 | void | |
177 | MetaRecord::packRecord(WriteSection &inWriteSection, | |
178 | const CSSM_DB_RECORD_ATTRIBUTE_DATA *inAttributes, | |
179 | const CssmData *inData) const | |
180 | { | |
181 | uint32 aDataSize; | |
182 | if (inData) | |
427c49bc | 183 | aDataSize = (uint32)inData->Length; |
b1ab9ed8 A |
184 | else |
185 | aDataSize = 0; | |
186 | ||
187 | inWriteSection.put(OffsetDataSize, aDataSize); | |
427c49bc | 188 | uint32 anOffset = (uint32)(OffsetAttributeOffsets + AtomSize * mAttributeVector.size()); |
b1ab9ed8 A |
189 | if (aDataSize) |
190 | anOffset = inWriteSection.put(anOffset, aDataSize, inData->Data); | |
191 | ||
192 | vector<uint32> aNumValues(mAttributeVector.size(), ~(uint32)0); | |
193 | vector<CSSM_DATA_PTR> aValues(mAttributeVector.size()); | |
194 | uint32 anIndex; | |
195 | ||
196 | if (inAttributes == NULL) | |
197 | inWriteSection.put(OffsetSemanticInformation, 0); | |
198 | else | |
199 | { | |
200 | inWriteSection.put(OffsetSemanticInformation, inAttributes->SemanticInformation); | |
201 | ||
202 | // Put the supplied attribute values into the list of attributes | |
203 | // and values. | |
204 | anIndex = inAttributes->NumberOfAttributes; | |
205 | // Make sure that AttributeData is a valid array. | |
206 | if (anIndex > 0) | |
207 | Required(inAttributes->AttributeData); | |
208 | ||
209 | while (anIndex-- > 0) | |
210 | { | |
211 | CSSM_DB_ATTRIBUTE_DATA &anAttribute = inAttributes->AttributeData[anIndex]; | |
212 | uint32 anAttributeIndex = attributeIndex(anAttribute.Info); | |
213 | // Make sure that the caller specified the attribute values in the correct format. | |
214 | if (anAttribute.Info.AttributeFormat != mAttributeVector[anAttributeIndex]->attributeFormat()) | |
215 | CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); | |
216 | ||
217 | // If this attribute was specified before, throw. | |
218 | if (aNumValues[anAttributeIndex] != ~(uint32)0) | |
219 | CssmError::throwMe(CSSMERR_DL_FIELD_SPECIFIED_MULTIPLE); | |
220 | ||
221 | aNumValues[anAttributeIndex] = anAttribute.NumberOfValues; | |
222 | aValues[anAttributeIndex] = anAttribute.Value; | |
223 | } | |
224 | } | |
225 | ||
226 | for (anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex) | |
227 | { | |
228 | const MetaAttribute &aMetaAttribute = *mAttributeVector[anIndex]; | |
229 | uint32 aNumberOfValues = aNumValues[anIndex]; | |
230 | // Now call the parsingmodule for each attribute that | |
231 | // wasn't explicitly specified and that has a parsingmodule. | |
232 | if (aNumberOfValues == ~(uint32)0) | |
233 | aNumberOfValues = aDataSize == 0 ? 0 : aMetaAttribute.parse(*inData, aValues[anIndex]); | |
234 | ||
235 | // XXX When do we throw CSSMERR_DL_MISSING_VALUE? Maybe if an | |
236 | // attribute is part of a unique index. | |
237 | ||
238 | // Now we have a valuelist for this attribute. Let's encode it. | |
239 | aMetaAttribute.packAttribute(inWriteSection, anOffset, aNumberOfValues, aValues[anIndex]); | |
240 | } | |
241 | ||
242 | inWriteSection.put(OffsetRecordSize, anOffset); | |
243 | inWriteSection.size(anOffset); | |
244 | } | |
245 | ||
246 | inline void | |
247 | MetaRecord::unpackAttribute(const ReadSection &inReadSection, | |
248 | Allocator &inAllocator, | |
249 | CSSM_DB_ATTRIBUTE_DATA &inoutAttribute) const | |
250 | { | |
251 | const MetaAttribute &aMetaAttribute = metaAttribute(inoutAttribute.Info); | |
252 | // XXX: See ISSUES on whether AttributeFormat should be an outputvalue or not. | |
253 | inoutAttribute.Info.AttributeFormat = aMetaAttribute.attributeFormat(); | |
254 | aMetaAttribute.unpackAttribute(inReadSection, inAllocator, | |
255 | inoutAttribute.NumberOfValues, | |
256 | inoutAttribute.Value); | |
257 | } | |
258 | ||
259 | void | |
260 | MetaRecord::unpackRecord(const ReadSection &inReadSection, | |
261 | Allocator &inAllocator, | |
262 | CSSM_DB_RECORD_ATTRIBUTE_DATA_PTR inoutAttributes, | |
263 | CssmData *inoutData, | |
264 | CSSM_QUERY_FLAGS inQueryFlags) const | |
265 | { | |
266 | // XXX Use POD wrapper for inoutAttributes here. | |
267 | TrackingAllocator anAllocator(inAllocator); | |
268 | ||
269 | try | |
270 | { | |
271 | if (inoutData) | |
272 | { | |
273 | // XXX Treat KEY records specially. | |
274 | ||
275 | // If inQueryFlags & CSSM_QUERY_RETURN_DATA is true return the raw | |
276 | // key bits in the CSSM_KEY structure | |
277 | Range aDataRange = dataRange(inReadSection); | |
278 | inoutData->Length = aDataRange.mSize; | |
279 | inoutData->Data = inReadSection.allocCopyRange(aDataRange, anAllocator); | |
280 | } | |
281 | ||
282 | if (inoutAttributes) | |
283 | { | |
284 | inoutAttributes->DataRecordType = dataRecordType(); | |
285 | inoutAttributes->SemanticInformation = semanticInformation(inReadSection); | |
286 | uint32 anIndex = inoutAttributes->NumberOfAttributes; | |
287 | ||
288 | // Make sure that AttributeData is a valid array. | |
289 | if (anIndex > 0 && inoutAttributes->AttributeData == NULL) | |
290 | CssmError::throwMe(CSSM_ERRCODE_INVALID_POINTER); | |
291 | ||
292 | while (anIndex-- > 0) | |
293 | { | |
294 | unpackAttribute(inReadSection, anAllocator, | |
295 | inoutAttributes->AttributeData[anIndex]); | |
296 | } | |
297 | } | |
298 | } | |
299 | catch (CssmError e) | |
300 | { | |
301 | if (e.osStatus() != CSSMERR_DL_DATABASE_CORRUPT) | |
302 | { | |
303 | // clear all pointers so that nothing dangles back to the user | |
304 | if (inoutData) | |
305 | { | |
306 | inoutData->Data = NULL; | |
307 | } | |
308 | ||
309 | if (inoutAttributes) | |
310 | { | |
311 | unsigned i; | |
312 | for (i = 0; i < inoutAttributes->NumberOfAttributes; ++i) | |
313 | { | |
314 | CSSM_DB_ATTRIBUTE_DATA& data = inoutAttributes->AttributeData[i]; | |
315 | ||
316 | unsigned j; | |
317 | for (j = 0; j < data.NumberOfValues; ++j) | |
318 | { | |
319 | data.Value[j].Data = NULL; | |
320 | } | |
321 | ||
322 | data.Value = NULL; | |
323 | ||
324 | if (data.Info.AttributeNameFormat == CSSM_DB_ATTRIBUTE_NAME_AS_STRING) | |
325 | { | |
326 | data.Info.Label.AttributeName = NULL; | |
327 | } | |
328 | } | |
329 | } | |
330 | } | |
331 | ||
332 | throw; | |
333 | } | |
334 | catch (...) | |
335 | { | |
336 | // clear all pointers so that nothing dangles back to the user | |
337 | if (inoutData) | |
338 | { | |
339 | inoutData->Data = NULL; | |
340 | } | |
341 | ||
342 | if (inoutAttributes) | |
343 | { | |
344 | unsigned i; | |
345 | for (i = 0; i < inoutAttributes->NumberOfAttributes; ++i) | |
346 | { | |
347 | CSSM_DB_ATTRIBUTE_DATA& data = inoutAttributes->AttributeData[i]; | |
348 | ||
349 | unsigned j; | |
350 | for (j = 0; j < data.NumberOfValues; ++j) | |
351 | { | |
352 | data.Value[j].Data = NULL; | |
353 | } | |
354 | ||
355 | data.Value = NULL; | |
356 | ||
357 | if (data.Info.AttributeNameFormat == CSSM_DB_ATTRIBUTE_NAME_AS_STRING) | |
358 | { | |
359 | data.Info.Label.AttributeName = NULL; | |
360 | } | |
361 | } | |
362 | } | |
363 | ||
364 | throw; | |
365 | } | |
366 | ||
367 | ||
368 | // Don't free anything the trackingAllocator allocated when it is destructed. | |
369 | anAllocator.commit(); | |
370 | } | |
371 | ||
372 | // Return the index (0 though NumAttributes - 1) of the attribute | |
373 | // represented by inAttributeInfo | |
374 | ||
375 | #ifndef NDEBUG | |
376 | #define LOG_NAME_AS_STRING_FAIL | |
377 | #endif | |
378 | uint32 | |
379 | MetaRecord::attributeIndex(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const | |
380 | { | |
381 | uint32 anIndex; | |
382 | switch (inAttributeInfo.AttributeNameFormat) | |
383 | { | |
384 | case CSSM_DB_ATTRIBUTE_NAME_AS_STRING: | |
385 | { | |
386 | string aName(inAttributeInfo.Label.AttributeName); | |
387 | assert(aName.size() < 500); // MDS leak debug | |
388 | NameStringMap::const_iterator it = mNameStringMap.find(aName); | |
389 | if (it == mNameStringMap.end()) { | |
390 | #ifdef LOG_NAME_AS_STRING_FAIL | |
391 | printf("NAME_AS_STRING failure; attrName %s\n", | |
392 | inAttributeInfo.Label.AttributeName); | |
393 | for(it = mNameStringMap.begin(); | |
394 | it != mNameStringMap.end(); | |
395 | it++) { | |
396 | printf("name %s val %d\n", it->first.c_str(), it->second); | |
397 | } | |
398 | #endif | |
399 | CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); | |
400 | } | |
401 | anIndex = it->second; | |
402 | break; | |
403 | } | |
404 | case CSSM_DB_ATTRIBUTE_NAME_AS_OID: | |
405 | { | |
406 | const CssmOid &aName = CssmOid::overlay(inAttributeInfo.Label.AttributeOID); | |
407 | NameOIDMap::const_iterator it = mNameOIDMap.find(aName); | |
408 | if (it == mNameOIDMap.end()) | |
409 | CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); | |
410 | anIndex = it->second; | |
411 | break; | |
412 | } | |
413 | case CSSM_DB_ATTRIBUTE_NAME_AS_INTEGER: | |
414 | { | |
415 | uint32 aName = inAttributeInfo.Label.AttributeID; | |
416 | NameIntMap::const_iterator it = mNameIntMap.find(aName); | |
417 | if (it == mNameIntMap.end()) | |
418 | CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); | |
419 | anIndex = it->second; | |
420 | break; | |
421 | } | |
422 | default: | |
423 | CssmError::throwMe(CSSMERR_DL_INVALID_FIELD_NAME); | |
424 | break; | |
425 | } | |
426 | ||
427 | return anIndex; | |
428 | } | |
429 | ||
430 | const MetaAttribute & | |
431 | MetaRecord::metaAttribute(const CSSM_DB_ATTRIBUTE_INFO &inAttributeInfo) const | |
432 | { | |
433 | return *mAttributeVector[attributeIndex(inAttributeInfo)]; | |
434 | } | |
435 | ||
436 | // Create a packed record from the given inputs and the old packed record inReadSection. | |
437 | void | |
438 | MetaRecord::updateRecord(const ReadSection &inReadSection, | |
439 | WriteSection &inWriteSection, | |
440 | const CssmDbRecordAttributeData *inAttributes, | |
441 | const CssmData *inData, | |
442 | CSSM_DB_MODIFY_MODE inModifyMode) const | |
443 | { | |
444 | TrackingAllocator anAllocator(Allocator::standard()); | |
445 | ||
446 | // modify the opaque data associated with the record | |
447 | ||
448 | uint32 aDataSize; | |
449 | const uint8 *aDataData = NULL; | |
450 | ||
451 | if (inData) | |
452 | { | |
453 | // prepare to write new data | |
427c49bc | 454 | aDataSize = (uint32)inData->Length; |
b1ab9ed8 A |
455 | aDataData = inData->Data; |
456 | } | |
457 | else | |
458 | { | |
459 | // prepare to copy old data | |
460 | Range aDataRange = dataRange(inReadSection); | |
461 | aDataSize = aDataRange.mSize; | |
462 | if (aDataSize) | |
463 | aDataData = inReadSection.range(aDataRange); | |
464 | } | |
465 | ||
466 | // compute the data offset; this will keep a running total of the record size | |
427c49bc | 467 | uint32 anOffset = (uint32)(OffsetAttributeOffsets + AtomSize * mAttributeVector.size()); |
b1ab9ed8 A |
468 | |
469 | // write the appropriate data to the new record | |
470 | inWriteSection.put(OffsetDataSize, aDataSize); | |
471 | if (aDataSize) | |
472 | anOffset = inWriteSection.put(anOffset, aDataSize, aDataData); | |
473 | ||
474 | // unpack the old attributes since some of them may need to be preserved | |
475 | ||
476 | auto_array<CssmDbAttributeData> attributeData(mAttributeVector.size()); | |
477 | ||
427c49bc | 478 | for (size_t anAttributeIndex = mAttributeVector.size(); anAttributeIndex-- > 0; ) |
b1ab9ed8 A |
479 | { |
480 | // unpack the old attribute data for this attribute index | |
481 | const MetaAttribute &attribute = *mAttributeVector[anAttributeIndex]; | |
482 | attribute.unpackAttribute(inReadSection, anAllocator, | |
483 | attributeData[anAttributeIndex].NumberOfValues, | |
484 | attributeData[anAttributeIndex].Value); | |
485 | } | |
486 | ||
487 | // retrieve the currrent semantic information | |
488 | ||
489 | uint32 oldSemanticInformation = semanticInformation(inReadSection); | |
490 | ||
491 | // process each input attribute as necessary, based on the modification mode | |
492 | ||
493 | if (inAttributes == NULL) | |
494 | { | |
495 | // make sure the modification mode is NONE, otherwise it's an | |
496 | // error accordining to the spec | |
497 | if (inModifyMode != CSSM_DB_MODIFY_ATTRIBUTE_NONE) | |
498 | CssmError::throwMe(CSSMERR_DL_INVALID_MODIFY_MODE); | |
499 | } | |
500 | ||
501 | else { | |
502 | ||
503 | // modify the semantic information | |
504 | ||
505 | uint32 inSemanticInformation = inAttributes ? inAttributes->SemanticInformation : 0; | |
506 | ||
507 | if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD) | |
508 | oldSemanticInformation |= inSemanticInformation; | |
509 | ||
510 | else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE) | |
511 | oldSemanticInformation &= ~inSemanticInformation; | |
512 | ||
513 | else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE) | |
514 | oldSemanticInformation = inSemanticInformation; | |
515 | ||
516 | uint32 anIndex = inAttributes->NumberOfAttributes; | |
517 | if (anIndex > 0) | |
518 | Required(inAttributes->AttributeData); | |
519 | ||
520 | // modify the attributes | |
521 | ||
522 | while (anIndex-- > 0) { | |
523 | ||
524 | const CssmDbAttributeData &anAttribute = inAttributes->at(anIndex); | |
525 | uint32 anAttributeIndex = attributeIndex(anAttribute.info()); | |
526 | if (anAttribute.format() != mAttributeVector[anAttributeIndex]->attributeFormat()) | |
527 | CssmError::throwMe(CSSMERR_DL_INCOMPATIBLE_FIELD_FORMAT); | |
528 | ||
529 | CssmDbAttributeData &oldAttribute = attributeData[anAttributeIndex]; | |
530 | ||
531 | // if the modify mode is ADD, merge new values with pre-existing values | |
532 | ||
533 | if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_ADD) | |
534 | oldAttribute.add(anAttribute, anAllocator); | |
535 | ||
536 | // if the modify mode is DELETE, remove the indicated values, or remove | |
537 | // all values if none are specified | |
538 | ||
539 | else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_DELETE) | |
540 | { | |
541 | if (anAttribute.size() == 0) | |
542 | oldAttribute.deleteValues(anAllocator); | |
543 | else | |
544 | oldAttribute.deleteValues(anAttribute, anAllocator); | |
545 | } | |
546 | ||
547 | // if the modify mode is REPLACE, then replace the specified values, or | |
548 | // delete all values if no values are specified | |
549 | ||
550 | else if (inModifyMode == CSSM_DB_MODIFY_ATTRIBUTE_REPLACE) | |
551 | { | |
552 | oldAttribute.deleteValues(anAllocator); | |
553 | if (anAttribute.size() > 0) | |
554 | oldAttribute.add(anAttribute, anAllocator); | |
555 | else | |
556 | // The spec says "all values are deleted or the the value is replaced | |
557 | // with the default" but doesn't say which. We could call the parsing | |
558 | // module for the attribute here...if they were implemented! But instead | |
559 | // we choose "all values are deleted" and leave it at that. | |
560 | ; | |
561 | } | |
562 | } | |
563 | } | |
564 | ||
565 | // write the resulting attributes into the new record | |
566 | ||
567 | inWriteSection.put(OffsetSemanticInformation, oldSemanticInformation); | |
568 | ||
569 | for (uint32 anIndex = 0; anIndex < mAttributeVector.size(); ++anIndex) | |
570 | { | |
571 | const MetaAttribute &metaAttribute = *mAttributeVector[anIndex]; | |
572 | metaAttribute.packAttribute(inWriteSection, anOffset, | |
573 | attributeData[anIndex].NumberOfValues, | |
574 | attributeData[anIndex].Value); | |
575 | } | |
576 | ||
577 | inWriteSection.put(OffsetRecordSize, anOffset); | |
578 | inWriteSection.size(anOffset); | |
579 | } | |
580 |