1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkMetaData.h"
11#include "SkRefCnt.h"
12
13struct PtrPair {
14    void*               fPtr;
15    SkMetaData::PtrProc fProc;
16};
17
18void* SkMetaData::RefCntProc(void* ptr, bool doRef) {
19    SkASSERT(ptr);
20    SkRefCnt* refcnt = reinterpret_cast<SkRefCnt*>(ptr);
21
22    if (doRef) {
23        refcnt->ref();
24    } else {
25        refcnt->unref();
26    }
27    return ptr;
28}
29
30SkMetaData::SkMetaData() : fRec(NULL)
31{
32}
33
34SkMetaData::SkMetaData(const SkMetaData& src) : fRec(NULL)
35{
36    *this = src;
37}
38
39SkMetaData::~SkMetaData()
40{
41    this->reset();
42}
43
44void SkMetaData::reset()
45{
46    Rec* rec = fRec;
47    while (rec) {
48        if (kPtr_Type == rec->fType) {
49            PtrPair* pair = (PtrPair*)rec->data();
50            if (pair->fProc && pair->fPtr) {
51                pair->fPtr = pair->fProc(pair->fPtr, false);
52            }
53        }
54        Rec* next = rec->fNext;
55        Rec::Free(rec);
56        rec = next;
57    }
58    fRec = NULL;
59}
60
61SkMetaData& SkMetaData::operator=(const SkMetaData& src)
62{
63    this->reset();
64
65    const Rec* rec = src.fRec;
66    while (rec)
67    {
68        this->set(rec->name(), rec->data(), rec->fDataLen, (Type)rec->fType, rec->fDataCount);
69        rec = rec->fNext;
70    }
71    return *this;
72}
73
74void SkMetaData::setS32(const char name[], int32_t value)
75{
76    (void)this->set(name, &value, sizeof(int32_t), kS32_Type, 1);
77}
78
79void SkMetaData::setScalar(const char name[], SkScalar value)
80{
81    (void)this->set(name, &value, sizeof(SkScalar), kScalar_Type, 1);
82}
83
84SkScalar* SkMetaData::setScalars(const char name[], int count, const SkScalar values[])
85{
86    SkASSERT(count > 0);
87    if (count > 0)
88        return (SkScalar*)this->set(name, values, sizeof(SkScalar), kScalar_Type, count);
89    return NULL;
90}
91
92void SkMetaData::setString(const char name[], const char value[])
93{
94    (void)this->set(name, value, sizeof(char), kString_Type, strlen(value) + 1);
95}
96
97void SkMetaData::setPtr(const char name[], void* ptr, PtrProc proc) {
98    PtrPair pair = { ptr, proc };
99    (void)this->set(name, &pair, sizeof(PtrPair), kPtr_Type, 1);
100}
101
102void SkMetaData::setBool(const char name[], bool value)
103{
104    (void)this->set(name, &value, sizeof(bool), kBool_Type, 1);
105}
106
107void SkMetaData::setData(const char name[], const void* data, size_t byteCount) {
108    (void)this->set(name, data, sizeof(char), kData_Type, byteCount);
109}
110
111void* SkMetaData::set(const char name[], const void* data, size_t dataSize, Type type, int count)
112{
113    SkASSERT(name);
114    SkASSERT(dataSize);
115    SkASSERT(count > 0);
116
117    (void)this->remove(name, type);
118
119    size_t  len = strlen(name);
120    Rec*    rec = Rec::Alloc(sizeof(Rec) + dataSize * count + len + 1);
121
122#ifndef SK_DEBUG
123    rec->fType = SkToU8(type);
124#else
125    rec->fType = type;
126#endif
127    rec->fDataLen = SkToU8(dataSize);
128    rec->fDataCount = SkToU16(count);
129    if (data)
130        memcpy(rec->data(), data, dataSize * count);
131    memcpy(rec->name(), name, len + 1);
132
133    if (kPtr_Type == type) {
134        PtrPair* pair = (PtrPair*)rec->data();
135        if (pair->fProc && pair->fPtr) {
136            pair->fPtr = pair->fProc(pair->fPtr, true);
137        }
138    }
139
140    rec->fNext = fRec;
141    fRec = rec;
142    return rec->data();
143}
144
145bool SkMetaData::findS32(const char name[], int32_t* value) const
146{
147    const Rec* rec = this->find(name, kS32_Type);
148    if (rec)
149    {
150        SkASSERT(rec->fDataCount == 1);
151        if (value)
152            *value = *(const int32_t*)rec->data();
153        return true;
154    }
155    return false;
156}
157
158bool SkMetaData::findScalar(const char name[], SkScalar* value) const
159{
160    const Rec* rec = this->find(name, kScalar_Type);
161    if (rec)
162    {
163        SkASSERT(rec->fDataCount == 1);
164        if (value)
165            *value = *(const SkScalar*)rec->data();
166        return true;
167    }
168    return false;
169}
170
171const SkScalar* SkMetaData::findScalars(const char name[], int* count, SkScalar values[]) const
172{
173    const Rec* rec = this->find(name, kScalar_Type);
174    if (rec)
175    {
176        if (count)
177            *count = rec->fDataCount;
178        if (values)
179            memcpy(values, rec->data(), rec->fDataCount * rec->fDataLen);
180        return (const SkScalar*)rec->data();
181    }
182    return NULL;
183}
184
185bool SkMetaData::findPtr(const char name[], void** ptr, PtrProc* proc) const {
186    const Rec* rec = this->find(name, kPtr_Type);
187    if (rec) {
188        SkASSERT(rec->fDataCount == 1);
189        const PtrPair* pair = (const PtrPair*)rec->data();
190        if (ptr) {
191            *ptr = pair->fPtr;
192        }
193        if (proc) {
194            *proc = pair->fProc;
195        }
196        return true;
197    }
198    return false;
199}
200
201const char* SkMetaData::findString(const char name[]) const
202{
203    const Rec* rec = this->find(name, kString_Type);
204    SkASSERT(rec == NULL || rec->fDataLen == sizeof(char));
205    return rec ? (const char*)rec->data() : NULL;
206}
207
208bool SkMetaData::findBool(const char name[], bool* value) const
209{
210    const Rec* rec = this->find(name, kBool_Type);
211    if (rec)
212    {
213        SkASSERT(rec->fDataCount == 1);
214        if (value)
215            *value = *(const bool*)rec->data();
216        return true;
217    }
218    return false;
219}
220
221const void* SkMetaData::findData(const char name[], size_t* length) const {
222    const Rec* rec = this->find(name, kData_Type);
223    if (rec) {
224        SkASSERT(rec->fDataLen == sizeof(char));
225        if (length) {
226            *length = rec->fDataCount;
227        }
228        return rec->data();
229    }
230    return NULL;
231}
232
233const SkMetaData::Rec* SkMetaData::find(const char name[], Type type) const
234{
235    const Rec* rec = fRec;
236    while (rec)
237    {
238        if (rec->fType == type && !strcmp(rec->name(), name))
239            return rec;
240        rec = rec->fNext;
241    }
242    return NULL;
243}
244
245bool SkMetaData::remove(const char name[], Type type) {
246    Rec* rec = fRec;
247    Rec* prev = NULL;
248    while (rec) {
249        Rec* next = rec->fNext;
250        if (rec->fType == type && !strcmp(rec->name(), name)) {
251            if (prev) {
252                prev->fNext = next;
253            } else {
254                fRec = next;
255            }
256
257            if (kPtr_Type == type) {
258                PtrPair* pair = (PtrPair*)rec->data();
259                if (pair->fProc && pair->fPtr) {
260                    (void)pair->fProc(pair->fPtr, false);
261                }
262            }
263            Rec::Free(rec);
264            return true;
265        }
266        prev = rec;
267        rec = next;
268    }
269    return false;
270}
271
272bool SkMetaData::removeS32(const char name[])
273{
274    return this->remove(name, kS32_Type);
275}
276
277bool SkMetaData::removeScalar(const char name[])
278{
279    return this->remove(name, kScalar_Type);
280}
281
282bool SkMetaData::removeString(const char name[])
283{
284    return this->remove(name, kString_Type);
285}
286
287bool SkMetaData::removePtr(const char name[])
288{
289    return this->remove(name, kPtr_Type);
290}
291
292bool SkMetaData::removeBool(const char name[])
293{
294    return this->remove(name, kBool_Type);
295}
296
297bool SkMetaData::removeData(const char name[]) {
298    return this->remove(name, kData_Type);
299}
300
301///////////////////////////////////////////////////////////////////////////////
302
303SkMetaData::Iter::Iter(const SkMetaData& metadata) {
304    fRec = metadata.fRec;
305}
306
307void SkMetaData::Iter::reset(const SkMetaData& metadata) {
308    fRec = metadata.fRec;
309}
310
311const char* SkMetaData::Iter::next(SkMetaData::Type* t, int* count) {
312    const char* name = NULL;
313
314    if (fRec) {
315        if (t) {
316            *t = (SkMetaData::Type)fRec->fType;
317        }
318        if (count) {
319            *count = fRec->fDataCount;
320        }
321        name = fRec->name();
322
323        fRec = fRec->fNext;
324    }
325    return name;
326}
327
328///////////////////////////////////////////////////////////////////////////////
329
330SkMetaData::Rec* SkMetaData::Rec::Alloc(size_t size) {
331    return (Rec*)sk_malloc_throw(size);
332}
333
334void SkMetaData::Rec::Free(Rec* rec) {
335    sk_free(rec);
336}
337
338