1 /*
2 This file is part of the Okteta Kasten Framework, made within the KDE community.
3
4 SPDX-FileCopyrightText: 2011 Alex Richardson <alex.richardson@gmx.de>
5 SPDX-FileCopyrightText: 2016 Aaron Bishop <erroneous@gmail.com>
6
7 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
8 */
9
10 #include "ebcdicstringdata.hpp"
11 #include "stringdatainformation.hpp"
12 #include "../topleveldatainformation.hpp"
13 #include "../../structlogging.hpp"
14
15 #include <Okteta/Character>
16 #include <codecs/ebcdic1047charcodec.hpp>
17 #include <Okteta/AbstractByteArrayModel>
18
19 #include <KLocalizedString>
20 #include <QVarLengthArray>
21
EbcdicStringData(StringDataInformation * parent)22 EbcdicStringData::EbcdicStringData(StringDataInformation* parent)
23 : StringData(parent)
24 , mCodec(Okteta::EBCDIC1047CharCodec::create())
25 {
26 }
27
~EbcdicStringData()28 EbcdicStringData::~EbcdicStringData()
29 {
30 delete mCodec;
31 }
32
read(Okteta::AbstractByteArrayModel * input,Okteta::Address address,BitCount64 bitsRemaining)33 qint64 EbcdicStringData::read(Okteta::AbstractByteArrayModel* input, Okteta::Address address, BitCount64 bitsRemaining)
34 {
35 const int oldSize = count();
36 if (mMode == CharCount || mMode == ByteCount) { // same for ebcdic
37 mData.reserve(mLength.maxChars);
38 }
39 mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, oldSize, 0);
40 mParent->topLevelDataInformation()->_childCountChanged(mParent, oldSize, 0);
41
42 quint64 remaining = bitsRemaining;
43 Okteta::Address addr = address;
44 int count = 0;
45 mEofReached = false;
46 const int oldMax = mData.size();
47 if (((mMode & CharCount) && mLength.maxChars == 0) || ((mMode & ByteCount) && mLength.maxBytes == 0)) {
48 return 0; // nothing to read
49
50 }
51 bool eofAtStart = false;
52 if (bitsRemaining < 8) {
53 eofAtStart = true;
54 }
55
56 while (true) {
57 if (remaining < 8) {
58 mEofReached = true;
59 break;
60 }
61 uchar val = input->byte(addr);
62 bool terminate = false;
63
64 if (count < oldMax) {
65 mData[count] = val;
66 } else {
67 mData.append(val);
68 }
69
70 remaining -= 8;
71 addr++;
72 count++;
73
74 // now check if we have to terminate
75 if (mMode & Sequence) {
76 if ((quint32(val) & 0xff) == mTerminationCodePoint) {
77 terminate = true;
78 }
79 }
80 if ((mMode & CharCount) || (mMode & ByteCount)) {
81 if ((unsigned)count >= mLength.maxChars) {
82 terminate = true;
83 }
84 }
85 if (mMode == None) {
86 qCDebug(LOG_KASTEN_OKTETA_CONTROLLERS_STRUCTURES) << "no termination mode set!!";
87 Q_ASSERT(false);
88 }
89 if (terminate) {
90 break;
91 }
92 }
93
94 mData.resize(count);
95 mParent->topLevelDataInformation()->_childCountAboutToChange(mParent, 0, count);
96 mParent->topLevelDataInformation()->_childCountChanged(mParent, 0, count);
97
98 if (eofAtStart) {
99 return -1;
100 }
101 return (addr - address) * 8;
102 }
103
sizeAt(uint i) const104 BitCount32 EbcdicStringData::sizeAt(uint i) const
105 {
106 Q_ASSERT(i < count());
107 Q_UNUSED(i)
108 return 8;
109 }
110
size() const111 BitCount32 EbcdicStringData::size() const
112 {
113 return mData.size() * 8;
114 }
115
completeString(bool) const116 QString EbcdicStringData::completeString(bool) const
117 {
118 int max = mData.size();
119 QVarLengthArray<QChar> buf(max);
120 for (int i = 0; i < max; ++i) {
121 uchar val = mData.at(i);
122 buf[i] = mCodec->decode(val);
123 }
124
125 return QString(buf.constData(), max);
126 }
127
stringValue(int row) const128 QString EbcdicStringData::stringValue(int row) const
129 {
130 Q_ASSERT(row >= 0 && row < mData.size());
131 uchar val = mData.at(row);
132 return mCodec->decode(val);
133 }
134
charType() const135 QString EbcdicStringData::charType() const
136 {
137 return i18n("EBCDIC char");
138 }
139
count() const140 uint EbcdicStringData::count() const
141 {
142 return mData.size();
143 }
144
typeName() const145 QString EbcdicStringData::typeName() const
146 {
147 return i18n("EBCDIC string");
148 }
149