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