/misc/an2kconvert/convertutil/src/part1/Field.cxx

https://github.com/lessandro/nbis · C++ · 580 lines · 298 code · 73 blank · 209 comment · 64 complexity · b98a849dae2691646a8e26a1d8d88996 MD5 · raw file

  1. #include "part1/Field.hxx"
  2. namespace convert {
  3. namespace part1 {
  4. using namespace std;
  5. /**
  6. * Constructs a new empty Field.
  7. */
  8. Field::Field(FieldID const& fieldId)
  9. : fieldId(fieldId) {}
  10. /**
  11. * Constructs a new Field with a single Subfield.
  12. *
  13. * subfield: Subfield to add to the Field.
  14. */
  15. Field::Field(FieldID const& fieldId, auto_ptr<Subfield> subfield)
  16. : fieldId(fieldId) {
  17. addSubfield(subfield);
  18. }
  19. /**
  20. * Constructs a new Field with a single Subfield with a single Item.
  21. *
  22. * item: Item to add to the Subfield.
  23. */
  24. Field::Field(FieldID const& fieldId, auto_ptr<Item> item)
  25. : fieldId(fieldId) {
  26. addSubfield(item);
  27. }
  28. /**
  29. * Constructs a new Field with a single Subfield with a single Item containing
  30. * itemValue.
  31. *
  32. * itemValue: string containing the value of the item to be created in the
  33. * Subfield.
  34. */
  35. Field::Field(FieldID const& fieldId, string const& itemValue)
  36. : fieldId(fieldId) {
  37. addSubfield(itemValue);
  38. }
  39. /**
  40. * Constructs a new Field from Part 1 binary data. Data is parsed according
  41. * to the specified FieldType.
  42. *
  43. * bytes: string containing Part 1 binary data.
  44. * fieldType: FieldType to be used when parsing the data.
  45. */
  46. Field::Field(FieldID const& fieldId, string const& bytes, FieldType fieldType)
  47. : fieldId(fieldId) {
  48. switch(fieldType) {
  49. case BinaryImageField:
  50. decodeBinaryImageField(bytes);
  51. break;
  52. case BinaryU8Field:
  53. decodeBinaryU8Field(bytes);
  54. break;
  55. case BinaryU16Field:
  56. decodeBinaryU16Field(bytes);
  57. break;
  58. case BinaryU32Field:
  59. decodeBinaryU32Field(bytes);
  60. break;
  61. case BinaryVectorField:
  62. decodeBinaryVectorField(bytes);
  63. break;
  64. case TaggedAsciiField:
  65. decodeTaggedAsciiField(bytes);
  66. break;
  67. case TaggedImageField:
  68. decodeTaggedImageField(bytes);
  69. break;
  70. }
  71. }
  72. /**
  73. * Copy constructor.
  74. */
  75. Field::Field(Field const& field)
  76. : fieldId(field.getFieldID() ) {
  77. //Don't copy Fields with NULL Subfields
  78. for(int i = 0; i < field.subfieldsCount(); i++) {
  79. addSubfield(auto_ptr<Subfield>(new Subfield(field.getSubfield(i))));
  80. }
  81. }
  82. /**
  83. * Returns the length of the Field in bytes. The returned length is equal to
  84. * the size of the string returned by toBytesForFile(fieldType). It is an
  85. * error if the Field contains NULL Subfields.
  86. *
  87. * fieldType: FieldType to be used when determining the length of the Field.
  88. */
  89. size_t Field::getLength(FieldType fieldType) const {
  90. if(hasMissingSubfields()) {
  91. throw logic_error("Field.getLength(): Field has missing Subfields");
  92. }
  93. size_t length = 0;
  94. SubfieldType subfieldType;
  95. switch(fieldType) {
  96. case BinaryImageField:
  97. subfieldType = BinaryImageSubfield;
  98. break;
  99. case BinaryU8Field:
  100. subfieldType = BinaryU8Subfield;
  101. break;
  102. case BinaryU16Field:
  103. subfieldType = BinaryU16Subfield;
  104. break;
  105. case BinaryU32Field:
  106. subfieldType = BinaryU32Subfield;
  107. break;
  108. case BinaryVectorField:
  109. subfieldType = BinaryVectorSubfield;
  110. break;
  111. case TaggedAsciiField:
  112. length += fieldId.toBytesForFile().size();
  113. subfieldType = TaggedAsciiSubfield;
  114. break;
  115. case TaggedImageField:
  116. length += fieldId.toBytesForFile().size();
  117. subfieldType = TaggedImageSubfield;
  118. break;
  119. }
  120. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  121. Subfield const& subfield = *(*it);
  122. length += subfield.getLength(subfieldType);
  123. }
  124. return length;
  125. }
  126. /**
  127. * Returns the FieldID associated with the Field.
  128. */
  129. FieldID const& Field::getFieldID() const {
  130. return fieldId;
  131. }
  132. /**
  133. * Returns a string containing the Part 1 binary data representing the Field.
  134. * The data will be formatted according the specified FieldType. It is an
  135. * error if the Field contains NULL Subfields.
  136. *
  137. * fieldType: the FieldType to be used to format the Field data.
  138. */
  139. auto_ptr<string> Field::toBytesForFile(FieldType fieldType) const {
  140. if(hasMissingSubfields()) {
  141. throw logic_error("Field.toBytesForFile(): Field has missing Subfields");
  142. }
  143. switch(fieldType) {
  144. case BinaryImageField:
  145. return encodeBinaryImageField();
  146. case BinaryU8Field:
  147. return encodeBinaryU8Field();
  148. case BinaryU16Field:
  149. return encodeBinaryU16Field();
  150. case BinaryU32Field:
  151. return encodeBinaryU32Field();
  152. case BinaryVectorField:
  153. return encodeBinaryVectorField();
  154. case TaggedAsciiField:
  155. return encodeTaggedAsciiField();
  156. case TaggedImageField:
  157. return encodeTaggedImageField();
  158. }
  159. }
  160. /**
  161. * Returns the Subfield in the Field at index if it exists. It is an error
  162. * if the index is invalid or it contains a NULL Subfield. The returned Subfield
  163. * is const.
  164. *
  165. * index: index of the Subfield to be returned.
  166. */
  167. Subfield const& Field::getSubfield(size_t index) const {
  168. if(index >= subfields.size() || subfields[index] == NULL) {
  169. throw logic_error("Field.getSubfield(): invalid index");
  170. }
  171. return *subfields[index];
  172. }
  173. /**
  174. * Returns the Subfield in the Field at index if it exists. It is an error
  175. * if the index is invalid or it contains a NULL Subfield. The returned Subfield
  176. * is not const.
  177. *
  178. * index: index of the Subfield to be returned.
  179. */
  180. Subfield& Field::getSubfield(size_t index) {
  181. if(index >= subfields.size() || subfields[index] == NULL) {
  182. throw logic_error("Field.getSubfield(): invalid index");
  183. }
  184. return *subfields[index];
  185. }
  186. /**
  187. * Returns the number of Subfields in the Field.
  188. */
  189. size_t Field::subfieldsCount() const {
  190. return subfields.size();
  191. }
  192. /**
  193. * Adds a new Subfield to the Field. The new Subfield will be the last Subfield
  194. * in the Field.
  195. *
  196. * subfield: Subfield to add to the Field.
  197. */
  198. void Field::addSubfield(auto_ptr<Subfield> subfield) {
  199. subfields.push_back(subfield.release());
  200. }
  201. /**
  202. * Creates a new Subfield with a single Item and adds it to the Field. The
  203. * new Subfield will be the last Subfield in the Field.
  204. *
  205. * item: Item to add to the new Subfield.
  206. */
  207. void Field::addSubfield(auto_ptr<Item> item) {
  208. subfields.push_back(new Subfield(item));
  209. }
  210. /**
  211. * Creates a new Subfield with a single Item from the value string and adds
  212. * it to the Field. The new Subfield will be the last Subfield in the Field.
  213. *
  214. * value: a string containing the value of the new Subfield.
  215. */
  216. void Field::addSubfield(string const& value) {
  217. subfields.push_back(new Subfield(value));
  218. }
  219. /**
  220. * Adds a new Subfield to the Field. The new Subfield will be placed at the specified
  221. * index unless it is already occupied by another Subfield. If the index is already
  222. * occupied by another Subfield it is an error. If index is past the end of the
  223. * subfield vector, NULL elements will be added between the end of the vector
  224. * and index.
  225. *
  226. * subfield: Subfield to add to the Field.
  227. * subfieldIndex: position of the new Subfield in the Field.
  228. */
  229. void Field::insertSubfield(auto_ptr<Subfield> subfield, size_t subfieldIndex) {
  230. while(subfields.size() <= subfieldIndex) {
  231. subfields.push_back(NULL);
  232. }
  233. if(subfields[subfieldIndex] != NULL) {
  234. throw logic_error("Field.insertSubfield(): cannot replace existing Subfield");
  235. }
  236. subfields[subfieldIndex] = subfield.release();
  237. }
  238. /**
  239. * Adds a new Item to the Field. If there is no Subfield at subfieldIndex,
  240. * a new Subfield is added at that index. The new Item is added at itemIndex
  241. * unless it is already occupied by another Item. If the index is already
  242. * occupied by another Item it is an error. If subfieldIndex is past the end
  243. * of the subfield vector, NULL elements will be added between the end of the
  244. * vector and subfieldIndex. If itemIndex is past the end of the item vector,
  245. * NULL elements will be added between the end of the vector and itemIndex.
  246. *
  247. * item: Item to add.
  248. * subfieldIndex: index of the Subfield in the Field.
  249. * itemIndex: index of the Item in the Subfield.
  250. */
  251. void Field::insertItem(auto_ptr<Item> item, size_t subfieldIndex, size_t itemIndex) {
  252. if(subfieldIndex >= subfields.size() || subfields[subfieldIndex] == NULL) {
  253. insertSubfield(auto_ptr<Subfield>(new Subfield()), subfieldIndex);
  254. }
  255. Subfield& subfield = *subfields[subfieldIndex];
  256. subfield.insertItem(item, itemIndex);
  257. }
  258. void Field::appendItem(string const& value, size_t subfieldIndex, size_t itemIndex) {
  259. if(subfieldIndex >= subfields.size() || subfields[subfieldIndex] == NULL) {
  260. insertSubfield(auto_ptr<Subfield>(new Subfield()), subfieldIndex);
  261. }
  262. Subfield& subfield = *subfields[subfieldIndex];
  263. subfield.appendItem(value, itemIndex);
  264. }
  265. /**
  266. * Equality comparison operator. Returns true if the fieldIds are the same.
  267. *
  268. * field: Field to compare.
  269. */
  270. bool Field::operator==(Field const& field) const {
  271. return this->fieldId == field.getFieldID();
  272. }
  273. /**
  274. * Inequality comparison operator. Returns the opposite of the equality comparison
  275. * operator.
  276. *
  277. * field: Field to compare.
  278. */
  279. bool Field::operator!=(Field const& field) const {
  280. return !(*this == field);
  281. }
  282. /**
  283. * Destructor.
  284. */
  285. Field::~Field() {
  286. deleteContents<Subfield*>(subfields);
  287. }
  288. /**
  289. * Returns true if the vector of subfields contains a NULL pointer.
  290. */
  291. bool Field::hasMissingSubfields() const {
  292. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  293. Subfield* subfield = *it;
  294. if(subfield == NULL) {
  295. return true;
  296. }
  297. }
  298. return false;
  299. }
  300. /**
  301. * Parses Part 1 binary data representing a binary image field.
  302. *
  303. * bytes: string containing Part 1 data.
  304. */
  305. void Field::decodeBinaryImageField(string const& bytes) {
  306. subfields.push_back(new Subfield(bytes, BinaryImageSubfield));
  307. }
  308. /**
  309. * Parses Part 1 binary data representing a binary U8 field. bytes must contain
  310. * at least 1 character.
  311. *
  312. * bytes: string containing Part 1 data.
  313. */
  314. void Field::decodeBinaryU8Field(string const& bytes) {
  315. if(bytes.empty()) {
  316. throw logic_error("Field.decodeBinaryU8Field(): invalid argument");
  317. //binary U8 field must contain at least 1 subfield
  318. //and each binary U8 subfield must be 1 byte
  319. }
  320. for(int i = 0; i < bytes.size(); i++) {
  321. subfields.push_back(new Subfield(string(bytes, i, 1), BinaryU8Subfield));
  322. }
  323. }
  324. /**
  325. * Parses Part 1 binary data representing a binary U16 field. bytes must contain
  326. * at least 2 characters and its length must be divisible by 2.
  327. *
  328. * bytes: string containing Part 1 data.
  329. */
  330. void Field::decodeBinaryU16Field(string const& bytes) {
  331. if(bytes.empty() || bytes.size() % 2 != 0) {
  332. throw logic_error("Field.decodeBinaryU16Field(): invalid argument");
  333. //binary U16 field must contain at least 1 subfield
  334. //and each binary U16 subfield must be 2 bytes
  335. }
  336. for(int i = 0; i < bytes.size(); i += 2) {
  337. subfields.push_back(new Subfield(string(bytes, i, 2), BinaryU16Subfield));
  338. }
  339. }
  340. /**
  341. * Parses Part 1 binary data representing a binary U32 field. bytes must contain
  342. * at least 4 characters and its length must be divisible by 4.
  343. *
  344. * bytes: string containing Part 1 data.
  345. */
  346. void Field::decodeBinaryU32Field(string const& bytes) {
  347. if(bytes.empty() || bytes.size() % 4 != 0) {
  348. throw logic_error("Field.decodeBinaryU32Field(): invalid argument");
  349. //binary U32 field must contain at least 1 subfield
  350. //and each binary U32 subfield must be 4 bytes
  351. }
  352. for(int i = 0; i < bytes.size(); i += 4) {
  353. subfields.push_back(new Subfield(string(bytes, i, 4), BinaryU32Subfield));
  354. }
  355. }
  356. /**
  357. * Parses Part 1 binary data representing a binary vector field. bytes must
  358. * contain at least 5 characters and its length must be divisible by 5.
  359. *
  360. * bytes: string containing Part 1 data.
  361. */
  362. void Field::decodeBinaryVectorField(string const& bytes) {
  363. if(bytes.empty() || bytes.size() % 5 != 0) {
  364. throw logic_error("Field.decodeBinaryVectorField(): invalid argument");
  365. //binary vector field must contain at least 1 subfield
  366. //and each binary vector subfield must be 5 bytes
  367. }
  368. for(int i = 0; i < bytes.size(); i += 5) {
  369. subfields.push_back(new Subfield(string(bytes, i, 5), BinaryVectorSubfield));
  370. }
  371. }
  372. /**
  373. * Parses Part 1 binary data representing a tagged ASCII field. String should
  374. * not be terminated with the field separator character (GS).
  375. *
  376. * bytes: string containing Part 1 data.
  377. */
  378. void Field::decodeTaggedAsciiField(string const& bytes) {
  379. auto_ptr<vector<string> > subfieldBytes = split(bytes, RS);
  380. for(vector<string>::const_iterator it = subfieldBytes->begin(); it != subfieldBytes->end(); it++) {
  381. string const& s = *it;
  382. subfields.push_back(new Subfield(s, TaggedAsciiSubfield));
  383. }
  384. }
  385. /**
  386. * Parses Part 1 binary data representing a tagged image field. String should
  387. * not be terminated with the field separator character (GS).
  388. *
  389. * bytes: string containing Part 1 data.
  390. */
  391. void Field::decodeTaggedImageField(string const& bytes) {
  392. subfields.push_back(new Subfield(bytes, TaggedImageSubfield));
  393. }
  394. /**
  395. * Creates a string containing Part 1 data representing a binary image field.
  396. * Field must contain exactly 1 Subfield.
  397. */
  398. auto_ptr<string> Field::encodeBinaryImageField() const {
  399. if(subfields.size() != 1) {
  400. throw logic_error("Field.encodeBinaryImageField(): wrong number of Subfields");
  401. //there must be exactly 1 subfield in an image field
  402. }
  403. return subfields[0]->toBytesForFile(BinaryImageSubfield);
  404. }
  405. /**
  406. * Creates a string containing Part 1 data representing a binary U8 field.
  407. * Field must contain at least 1 Subfield.
  408. */
  409. auto_ptr<string> Field::encodeBinaryU8Field() const {
  410. if(subfields.empty()) {
  411. throw logic_error("Field.encodeBinaryU8Field(): wrong number of Subfields");
  412. //there must be at least 1 subfield in an binary U8 field
  413. }
  414. auto_ptr<string> bytes(new string);
  415. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  416. Subfield const& subfield = *(*it);
  417. *bytes += *(subfield.toBytesForFile(BinaryU8Subfield));
  418. }
  419. return bytes;
  420. }
  421. /**
  422. * Creates a string containing Part 1 data representing a binary U16 field.
  423. * Field must contain at least 1 Subfield.
  424. */
  425. auto_ptr<string> Field::encodeBinaryU16Field() const {
  426. if(subfields.empty()) {
  427. throw logic_error("Field.encodeBinaryU16Field(): wrong number of Subfields");
  428. //there must be at least 1 subfield in an binary U16 field
  429. }
  430. auto_ptr<string> bytes(new string);
  431. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  432. Subfield const& subfield = *(*it);
  433. *bytes += *(subfield.toBytesForFile(BinaryU16Subfield));
  434. }
  435. return bytes;
  436. }
  437. /**
  438. * Creates a string containing Part 1 data representing a binary U16 field.
  439. * Field must contain at least 1 Subfield.
  440. */
  441. auto_ptr<string> Field::encodeBinaryU32Field() const {
  442. if(subfields.empty()) {
  443. throw logic_error("Field.encodeBinaryU32Field(): wrong number of Subfields");
  444. //there must be at least 1 subfield in an binary U32 field
  445. }
  446. auto_ptr<string> bytes(new string);
  447. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  448. Subfield const& subfield = *(*it);
  449. *bytes += *(subfield.toBytesForFile(BinaryU32Subfield));
  450. }
  451. return bytes;
  452. }
  453. /**
  454. * Creates a string containing Part 1 data representing a binary vector field.
  455. * Field must contain at least 1 Subfield.
  456. */
  457. auto_ptr<string> Field::encodeBinaryVectorField() const {
  458. if(subfields.empty()) {
  459. throw logic_error("Field.encodeBinaryVectorField(): wrong number of Subfields");
  460. //there must be at least 1 subfield in an binary vector field
  461. }
  462. auto_ptr<string> bytes(new string);
  463. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  464. Subfield const& subfield = *(*it);
  465. *bytes += *(subfield.toBytesForFile(BinaryVectorSubfield));
  466. }
  467. return bytes;
  468. }
  469. /**
  470. * Creates a string containing Part 1 data representing a tagged ASCII field.
  471. * Created string is terminated with the field separator character (GS). Field
  472. * must contain at least 1 Subfield.
  473. */
  474. auto_ptr<string> Field::encodeTaggedAsciiField() const {
  475. if(subfields.empty()) {
  476. throw logic_error("Field.encodeTaggedAsciiField(): wrong number of Subfields");
  477. //there must be at least 1 subfield in a tagged ascii field
  478. }
  479. auto_ptr<string> bytes(new string);
  480. *bytes += fieldId.toBytesForFile();
  481. for(vector<Subfield*>::const_iterator it = subfields.begin(); it != subfields.end(); it++) {
  482. Subfield const& subfield = *(*it);
  483. *bytes += *(subfield.toBytesForFile(TaggedAsciiSubfield));
  484. }
  485. bytes->resize(bytes->size() - 1);
  486. bytes->push_back(GS);
  487. return bytes;
  488. }
  489. /**
  490. * Creates a string containing Part 1 data representing a tagged image field.
  491. * Created string is terminated with the field separator character (GS). Field
  492. * must contain exactly 1 Subfield.
  493. */
  494. auto_ptr<string> Field::encodeTaggedImageField() const {
  495. if(subfields.size() != 1) {
  496. throw logic_error("Field.encodeTaggedImageField(): wrong number of Subfields");
  497. //there must be exactly 1 subfield in an image field
  498. }
  499. auto_ptr<string> bytes(new string);
  500. *bytes += fieldId.toBytesForFile();
  501. *bytes += *(subfields[0]->toBytesForFile(TaggedImageSubfield));
  502. bytes->resize(bytes->size() - 1);
  503. bytes->push_back(GS);
  504. return bytes;
  505. }
  506. }
  507. }